From 92258e99e639795f4119a86a1c44d5015b29ffdc Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Sat, 6 Jul 2019 04:27:00 +0000 Subject: [PATCH 1/9] Specify correct MIB length Could have resulted in a buffer overflow if the FreeBSD kernel returned more bytes than expected. --- freebsd/FreeBSDProcessList.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 9fef324a..26019b68 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -121,7 +121,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui len = sizeof(fpl->memZfsArc); if (sysctlbyname("kstat.zfs.misc.arcstats.size", &fpl->memZfsArc, &len, NULL, 0) == 0 && fpl->memZfsArc != 0) { - sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); + len = 5; sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); fpl->zfsArcEnabled = 1; } else { fpl->zfsArcEnabled = 0; From a93edde1a21e533472b5d443002032260b5bd066 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Sat, 6 Jul 2019 04:27:49 +0000 Subject: [PATCH 2/9] Support ZFS ARC stats on FreeBSD New meter displays same ARC stats as FreeBSD top(1). Can be extended to other platforms that support ZFS. Pulling kstat.zfs.misc.arcstats.c_max as the meter total, so the meter has a meaningful value to work up to. The Text meter displays, first, the maximum ARC size (Meter.total), then second, the total ARC used, using the difference between Meter.maxItems and Meter.curItems to "hide" the used value from the Bar and Graph drawing functions by using an index in Meter.values[] that is beyond curItems - 1, but less than maxItems - 1. --- CRT.c | 35 ++++++++++++++++ CRT.h | 5 +++ Makefile.am | 10 ++++- freebsd/FreeBSDProcessList.c | 48 ++++++++++++++++++++- freebsd/FreeBSDProcessList.h | 6 +++ freebsd/Platform.c | 19 +++++++++ freebsd/Platform.h | 2 + zfs/ZfsArcMeter.c | 81 ++++++++++++++++++++++++++++++++++++ zfs/ZfsArcMeter.h | 18 ++++++++ 9 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 zfs/ZfsArcMeter.c create mode 100644 zfs/ZfsArcMeter.h diff --git a/CRT.c b/CRT.c index ca9a10dd..b9017aa4 100644 --- a/CRT.c +++ b/CRT.c @@ -128,6 +128,11 @@ typedef enum ColorElements_ { CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, + ZFS_MFU, + ZFS_MRU, + ZFS_ANON, + ZFS_HEADER, + ZFS_OTHER, LAST_COLORELEMENT } ColorElements; @@ -232,6 +237,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Magenta,Black), [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), + [ZFS_MFU] = ColorPair(Blue,Black), + [ZFS_MRU] = ColorPair(Yellow,Black), + [ZFS_ANON] = ColorPair(Magenta,Black), + [ZFS_HEADER] = ColorPair(Cyan,Black), + [ZFS_OTHER] = ColorPair(Magenta,Black), }, [COLORSCHEME_MONOCHROME] = { [RESET_COLOR] = A_NORMAL, @@ -291,6 +301,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = A_BOLD, [CPU_STEAL] = A_REVERSE, [CPU_GUEST] = A_REVERSE, + [ZFS_MFU] = A_NORMAL, + [ZFS_MRU] = A_NORMAL, + [ZFS_ANON] = A_DIM, + [ZFS_HEADER] = A_BOLD, + [ZFS_OTHER] = A_DIM, }, [COLORSCHEME_BLACKONWHITE] = { [RESET_COLOR] = ColorPair(Black,White), @@ -350,6 +365,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,White), [CPU_STEAL] = ColorPair(Cyan,White), [CPU_GUEST] = ColorPair(Cyan,White), + [ZFS_MFU] = ColorPair(Cyan,White), + [ZFS_MRU] = ColorPair(Yellow,White), + [ZFS_ANON] = ColorPair(Magenta,White), + [ZFS_HEADER] = ColorPair(Yellow,White), + [ZFS_OTHER] = ColorPair(Magenta,White), }, [COLORSCHEME_LIGHTTERMINAL] = { [RESET_COLOR] = ColorPair(Black,Black), @@ -409,6 +429,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_STEAL] = ColorPair(Black,Black), [CPU_GUEST] = ColorPair(Black,Black), + [ZFS_MFU] = ColorPair(Cyan,Black), + [ZFS_MRU] = ColorPair(Yellow,Black), + [ZFS_ANON] = A_BOLD | ColorPair(Magenta,Black), + [ZFS_HEADER] = ColorPair(Black,Black), + [ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Black), }, [COLORSCHEME_MIDNIGHT] = { [RESET_COLOR] = ColorPair(White,Blue), @@ -468,6 +493,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Black,Blue), [CPU_STEAL] = ColorPair(White,Blue), [CPU_GUEST] = ColorPair(White,Blue), + [ZFS_MFU] = A_BOLD | ColorPair(White,Blue), + [ZFS_MRU] = A_BOLD | ColorPair(Yellow,Blue), + [ZFS_ANON] = A_BOLD | ColorPair(Magenta,Blue), + [ZFS_HEADER] = A_BOLD | ColorPair(Yellow,Blue), + [ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Blue), }, [COLORSCHEME_BLACKNIGHT] = { [RESET_COLOR] = ColorPair(Cyan,Black), @@ -527,6 +557,11 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), + [ZFS_MFU] = ColorPair(Blue,Black), + [ZFS_MRU] = ColorPair(Yellow,Black), + [ZFS_ANON] = ColorPair(Magenta,Black), + [ZFS_HEADER] = ColorPair(Yellow,Black), + [ZFS_OTHER] = ColorPair(Magenta,Black), }, [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. }; diff --git a/CRT.h b/CRT.h index 933fe068..2275349a 100644 --- a/CRT.h +++ b/CRT.h @@ -116,6 +116,11 @@ typedef enum ColorElements_ { CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, + ZFS_MFU, + ZFS_MRU, + ZFS_ANON, + ZFS_HEADER, + ZFS_OTHER, LAST_COLORELEMENT } ColorElements; diff --git a/Makefile.am b/Makefile.am index 7d19600f..ad23d19b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,10 @@ TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ EnvScreen.h InfoScreen.h XAlloc.h +zfs_platform_sources = zfs/ZfsArcMeter.c + +zfs_platform_headers = zfs/ZfsArcMeter.h + all_platform_headers = # Linux @@ -68,13 +72,15 @@ freebsd_platform_headers = \ freebsd/FreeBSDProcessList.h \ freebsd/FreeBSDProcess.h \ freebsd/FreeBSDCRT.h \ - freebsd/Battery.h + freebsd/Battery.h \ + $(zfs_platform_headers) all_platform_headers += $(freebsd_platform_headers) if HTOP_FREEBSD myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \ -freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c +freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \ +$(zfs_platform_sources) myhtopplatheaders = $(freebsd_platform_headers) endif diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 26019b68..94cbaa19 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -53,6 +53,12 @@ typedef struct FreeBSDProcessList_ { unsigned long long int memFree; 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; CPUData* cpus; @@ -81,6 +87,12 @@ static int MIB_vm_stats_vm_v_free_count[4]; static int MIB_vfs_bufspace[2]; static int MIB_kstat_zfs_misc_arcstats_size[5]; +static int MIB_vfs_zfs_arc_max[3]; +static int MIB_kstat_zfs_misc_arcstats_mfu_size[5]; +static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; +static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; +static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; +static int MIB_kstat_zfs_misc_arcstats_other_size[5]; static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; @@ -123,6 +135,16 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui NULL, 0) == 0 && fpl->memZfsArc != 0) { len = 5; sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); fpl->zfsArcEnabled = 1; + + len = 3; + sysctlnametomib("vfs.zfs.arc_max", MIB_vfs_zfs_arc_max, &len); + + len = 5; + sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); } else { fpl->zfsArcEnabled = 0; } @@ -323,8 +345,30 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { fpl->memZfsArc /= 1024; fpl->memWire -= fpl->memZfsArc; pl->cachedMem += fpl->memZfsArc; - // maybe when we learn how to make custom memory meter - // we could do custom arc breakdown? + + len = sizeof(fpl->zfsArcMax); + sysctl(MIB_vfs_zfs_arc_max, 3, &(fpl->zfsArcMax), &len , NULL, 0); + fpl->zfsArcMax /= 1024; + + len = sizeof(fpl->zfsArcMFU); + sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(fpl->zfsArcMFU), &len , NULL, 0); + fpl->zfsArcMFU /= 1024; + + len = sizeof(fpl->zfsArcMRU); + sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(fpl->zfsArcMRU), &len , NULL, 0); + fpl->zfsArcMRU /= 1024; + + len = sizeof(fpl->zfsArcAnon); + sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(fpl->zfsArcAnon), &len , NULL, 0); + fpl->zfsArcAnon /= 1024; + + len = sizeof(fpl->zfsArcHeader); + sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(fpl->zfsArcHeader), &len , NULL, 0); + fpl->zfsArcHeader /= 1024; + + len = sizeof(fpl->zfsArcOther); + sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(fpl->zfsArcOther), &len , NULL, 0); + fpl->zfsArcOther /= 1024; } pl->usedMem = fpl->memActive + fpl->memWire; diff --git a/freebsd/FreeBSDProcessList.h b/freebsd/FreeBSDProcessList.h index af343fb0..cf96a702 100644 --- a/freebsd/FreeBSDProcessList.h +++ b/freebsd/FreeBSDProcessList.h @@ -42,6 +42,12 @@ typedef struct FreeBSDProcessList_ { unsigned long long int memFree; 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; CPUData* cpus; diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 5dd6ca41..d8d2ed06 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -15,6 +15,7 @@ in the source distribution for its full text. #include "UptimeMeter.h" #include "ClockMeter.h" #include "HostnameMeter.h" +#include "zfs/ZfsArcMeter.h" #include "FreeBSDProcess.h" #include "FreeBSDProcessList.h" @@ -104,6 +105,7 @@ MeterClass* Platform_meterTypes[] = { &LeftCPUs2Meter_class, &RightCPUs2Meter_class, &BlankMeter_class, + &ZfsArcMeter_class, NULL }; @@ -197,6 +199,23 @@ void Platform_setSwapValues(Meter* this) { this->values[0] = pl->usedSwap; } +void Platform_setZfsArcValues(Meter* this) { + FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl; + + this->total = fpl->zfsArcMax; + this->values[0] = fpl->zfsArcMFU; + this->values[1] = fpl->zfsArcMRU; + this->values[2] = fpl->zfsArcAnon; + this->values[3] = fpl->zfsArcHeader; + this->values[4] = fpl->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] = fpl->memZfsArc; +} + void Platform_setTasksValues(Meter* this) { // TODO } diff --git a/freebsd/Platform.h b/freebsd/Platform.h index 1735e7e3..3dc7ebf2 100644 --- a/freebsd/Platform.h +++ b/freebsd/Platform.h @@ -44,6 +44,8 @@ void Platform_setMemoryValues(Meter* this); void Platform_setSwapValues(Meter* this); +void Platform_setZfsArcValues(Meter* this); + void Platform_setTasksValues(Meter* this); char* Platform_getProcessEnv(pid_t pid); diff --git a/zfs/ZfsArcMeter.c b/zfs/ZfsArcMeter.c new file mode 100644 index 00000000..e12c46e2 --- /dev/null +++ b/zfs/ZfsArcMeter.c @@ -0,0 +1,81 @@ +/* +htop - ZfsArcMeter.c +(C) 2004-2011 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "ZfsArcMeter.h" + +#include "CRT.h" +#include "Platform.h" + +#include +#include +#include +#include +#include + +/*{ +#include "Meter.h" +}*/ + +int ZfsArcMeter_attributes[] = { + ZFS_MFU, ZFS_MRU, ZFS_ANON, ZFS_HEADER, ZFS_OTHER +}; + +static void ZfsArcMeter_updateValues(Meter* this, char* buffer, int size) { + int written; + Platform_setZfsArcValues(this); + + written = Meter_humanUnit(buffer, this->values[5], size); + buffer += written; + if ((size -= written) > 0) { + *buffer++ = '/'; + size--; + Meter_humanUnit(buffer, this->total, size); + } +} + +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); +} + +MeterClass ZfsArcMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete, + .display = ZfsArcMeter_display, + }, + .updateValues = ZfsArcMeter_updateValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 6, + .total = 100.0, + .attributes = ZfsArcMeter_attributes, + .name = "ZFSARC", + .uiName = "ZFS ARC", + .caption = "ARC" +}; diff --git a/zfs/ZfsArcMeter.h b/zfs/ZfsArcMeter.h new file mode 100644 index 00000000..b89be223 --- /dev/null +++ b/zfs/ZfsArcMeter.h @@ -0,0 +1,18 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_ZfsArcMeter +#define HEADER_ZfsArcMeter +/* +htop - ZfsArcMeter.h +(C) 2004-2011 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Meter.h" + +extern int ZfsArcMeter_attributes[]; + +extern MeterClass ZfsArcMeter_class; + +#endif From 070fe90461182743fabb029415fc1bc59be14f3f Mon Sep 17 00:00:00 2001 From: Ross Williams 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 ad23d19b..b850815a 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 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 @@ -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 diff --git a/zfs/ZfsArcMeter.c b/zfs/ZfsArcMeter.c index e12c46e2..ebd80992 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 = { From fc8e9a2d3e25e35c0f9903baa345b1744b12b6cb Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Sun, 7 Jul 2019 17:30:37 -0400 Subject: [PATCH 4/9] ZFS arcstats for Darwin (macOS / OS X) --- Makefile.am | 6 ++- darwin/DarwinProcessList.c | 80 ++++++++++++++++++++++++++++++++++++++ darwin/DarwinProcessList.h | 21 ++++++++++ darwin/Platform.c | 19 +++++++++ darwin/Platform.h | 2 + 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index b850815a..b6d2117b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -134,14 +134,16 @@ darwin_platform_headers = \ darwin/DarwinProcess.h \ darwin/DarwinProcessList.h \ darwin/DarwinCRT.h \ - darwin/Battery.h + darwin/Battery.h \ + $(zfs_platform_headers) all_platform_headers += $(darwin_platform_headers) if HTOP_DARWIN AM_LDFLAGS += -framework IOKit -framework CoreFoundation myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \ -darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c +darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \ +$(zfs_platform_sources) myhtopplatheaders = $(darwin_platform_headers) endif diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 09884480..267e8e94 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -54,6 +54,7 @@ int CompareKernelVersion(short int major, short int minor, short int component) /*{ #include "ProcessList.h" +#include "zfs/ZfsArcStats.h" #include #include @@ -67,10 +68,28 @@ typedef struct DarwinProcessList_ { uint64_t kernel_threads; uint64_t user_threads; uint64_t global_diff; + + int zfsArcEnabled; + unsigned long long int zfsArcMax; + unsigned long long int zfsArcSize; + 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; + } DarwinProcessList; }*/ +static int MIB_kstat_zfs_misc_arcstats_c_max[5]; +static int MIB_kstat_zfs_misc_arcstats_size[5]; +static int MIB_kstat_zfs_misc_arcstats_mfu_size[5]; +static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; +static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; +static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; +static int MIB_kstat_zfs_misc_arcstats_other_size[5]; + void ProcessList_getHostInfo(host_basic_info_data_t *p) { mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT; @@ -131,8 +150,50 @@ struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) { return processes; } +static inline void DarwinProcessList_scanZfsArcstats(DarwinProcessList* dpl) { + size_t len; + + if (dpl->zfsArcEnabled) { + len = sizeof(dpl->zfsArcSize); + sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(dpl->zfsArcSize), &len , NULL, 0); + /* TODO: adjust reported memory in use to move ARC from wired to inactive + Like: + // In bytes + dpl->vm_stats.wire_count -= dpl->zfsArcSize / vm_page_size; + dpl->vm_stats.inactive_count += dpl->zfsArcSize / vm_page_size; + // Would purgable_count be more true? + // Then convert to KB: + */ + dpl->zfsArcSize /= 1024; + + len = sizeof(dpl->zfsArcMax); + sysctl(MIB_kstat_zfs_misc_arcstats_c_max, 5, &(dpl->zfsArcMax), &len , NULL, 0); + dpl->zfsArcMax /= 1024; + + len = sizeof(dpl->zfsArcMFU); + sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(dpl->zfsArcMFU), &len , NULL, 0); + dpl->zfsArcMFU /= 1024; + + len = sizeof(dpl->zfsArcMRU); + sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(dpl->zfsArcMRU), &len , NULL, 0); + dpl->zfsArcMRU /= 1024; + + len = sizeof(dpl->zfsArcAnon); + sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(dpl->zfsArcAnon), &len , NULL, 0); + dpl->zfsArcAnon /= 1024; + + len = sizeof(dpl->zfsArcHeader); + sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(dpl->zfsArcHeader), &len , NULL, 0); + dpl->zfsArcHeader /= 1024; + + len = sizeof(dpl->zfsArcOther); + sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(dpl->zfsArcOther), &len , NULL, 0); + dpl->zfsArcOther /= 1024; + } +} ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { + size_t len; DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList)); ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId); @@ -145,6 +206,24 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui /* Initialize the VM statistics */ ProcessList_getVMStats(&this->vm_stats); + /* Initialize the ZFS kstats, if zfs.kext loaded */ + len = sizeof(this->zfsArcSize); + if (sysctlbyname("kstat.zfs.misc.arcstats.size", &this->zfsArcSize, &len, + NULL, 0) == 0 && this->zfsArcSize != 0) { + this->zfsArcEnabled = 1; + + len = 5; + sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.c_max", MIB_kstat_zfs_misc_arcstats_c_max, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); + } else { + this->zfsArcEnabled = 0; + } + this->super.kernelThreads = 0; this->super.userlandThreads = 0; this->super.totalTasks = 0; @@ -173,6 +252,7 @@ void ProcessList_goThroughEntries(ProcessList* super) { dpl->prev_load = dpl->curr_load; ProcessList_allocateCPULoadInfo(&dpl->curr_load); ProcessList_getVMStats(&dpl->vm_stats); + DarwinProcessList_scanZfsArcstats(dpl); /* Get the time difference */ dpl->global_diff = 0; diff --git a/darwin/DarwinProcessList.h b/darwin/DarwinProcessList.h index c216a804..6686d05c 100644 --- a/darwin/DarwinProcessList.h +++ b/darwin/DarwinProcessList.h @@ -9,6 +9,17 @@ Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ +struct kern; + +void GetKernelVersion(struct kern *k); + +/* compare the given os version with the one installed returns: +0 if equals the installed version +positive value if less than the installed version +negative value if more than the installed version +*/ +int CompareKernelVersion(short int major, short int minor, short int component); + #include "ProcessList.h" #include #include @@ -23,6 +34,16 @@ typedef struct DarwinProcessList_ { uint64_t kernel_threads; uint64_t user_threads; uint64_t global_diff; + + int zfsArcEnabled; + unsigned long long int zfsArcMax; + unsigned long long int zfsArcSize; + 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; + } DarwinProcessList; diff --git a/darwin/Platform.c b/darwin/Platform.c index 1dce8b67..52d60a9b 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -15,6 +15,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "UptimeMeter.h" +#include "zfs/ZfsArcMeter.h" #include "DarwinProcessList.h" #include @@ -117,6 +118,7 @@ MeterClass* Platform_meterTypes[] = { &RightCPUsMeter_class, &LeftCPUs2Meter_class, &RightCPUs2Meter_class, + &ZfsArcMeter_class, &BlankMeter_class, NULL }; @@ -241,6 +243,23 @@ void Platform_setSwapValues(Meter* mtr) { mtr->values[0] = swapused.xsu_used / 1024; } +void Platform_setZfsArcValues(Meter* this) { + DarwinProcessList* dpl = (DarwinProcessList*) this->pl; + + this->total = dpl->zfsArcMax; + this->values[0] = dpl->zfsArcMFU; + this->values[1] = dpl->zfsArcMRU; + this->values[2] = dpl->zfsArcAnon; + this->values[3] = dpl->zfsArcHeader; + this->values[4] = dpl->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] = dpl->zfsArcSize; +} + char* Platform_getProcessEnv(pid_t pid) { char* env = NULL; diff --git a/darwin/Platform.h b/darwin/Platform.h index 1231217b..4acda2c4 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -48,6 +48,8 @@ void Platform_setMemoryValues(Meter* mtr); void Platform_setSwapValues(Meter* mtr); +void Platform_setZfsArcValues(Meter* mtr); + char* Platform_getProcessEnv(pid_t pid); #endif From a88d2e313df7f5f2b781d5b14ffe0e7710018c10 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Sun, 7 Jul 2019 23:27:00 +0000 Subject: [PATCH 5/9] Refactor common OpenZFS sysctl access Darwin and FreeBSD export zfs kstats through the same APIs, so moving functions into a common file. --- Makefile.am | 21 ++++----- darwin/DarwinProcessList.c | 82 +++--------------------------------- darwin/DarwinProcessList.h | 11 +---- darwin/Platform.c | 14 +++--- darwin/Platform.h | 2 +- freebsd/FreeBSDProcessList.c | 77 +++++---------------------------- freebsd/FreeBSDProcessList.h | 12 ++---- freebsd/Platform.c | 14 +++--- linux/LinuxProcessList.c | 40 ++++++++---------- linux/LinuxProcessList.h | 10 +---- linux/Platform.c | 14 +++--- zfs/ZfsArcStats.c | 19 +++++++++ zfs/ZfsArcStats.h | 23 ++++++++++ zfs/openzfs_sysctl.c | 81 +++++++++++++++++++++++++++++++++++ zfs/openzfs_sysctl.h | 18 ++++++++ 15 files changed, 215 insertions(+), 223 deletions(-) create mode 100644 zfs/ZfsArcStats.c create mode 100644 zfs/ZfsArcStats.h create mode 100644 zfs/openzfs_sysctl.c create mode 100644 zfs/openzfs_sysctl.h diff --git a/Makefile.am b/Makefile.am index b6d2117b..5eee6315 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,10 +36,6 @@ TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ EnvScreen.h InfoScreen.h XAlloc.h -zfs_platform_sources = zfs/ZfsArcMeter.c - -zfs_platform_headers = zfs/ZfsArcMeter.h - all_platform_headers = # Linux @@ -53,7 +49,8 @@ linux_platform_headers = \ linux/LinuxProcessList.h \ linux/LinuxCRT.h \ linux/Battery.h \ - $(zfs_platform_headers) + zfs/ZfsArcMeter.h \ + zfs/ZfsArcStats.h all_platform_headers += $(linux_platform_headers) @@ -61,7 +58,7 @@ 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 \ -$(zfs_platform_sources) +zfs/ZfsArcMeter.c zfs/ZfsArcStats.c myhtopplatheaders = $(linux_platform_headers) endif @@ -75,14 +72,16 @@ freebsd_platform_headers = \ freebsd/FreeBSDProcess.h \ freebsd/FreeBSDCRT.h \ freebsd/Battery.h \ - $(zfs_platform_headers) + zfs/ZfsArcMeter.h \ + zfs/ZfsArcStats.h \ + zfs/openzfs_sysctl.h all_platform_headers += $(freebsd_platform_headers) if HTOP_FREEBSD myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \ freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \ -$(zfs_platform_sources) +zfs/ZfsArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c myhtopplatheaders = $(freebsd_platform_headers) endif @@ -135,7 +134,9 @@ darwin_platform_headers = \ darwin/DarwinProcessList.h \ darwin/DarwinCRT.h \ darwin/Battery.h \ - $(zfs_platform_headers) + zfs/ZfsArcMeter.h \ + zfs/ZfsArcStats.h \ + zfs/openzfs_sysctl.h all_platform_headers += $(darwin_platform_headers) @@ -143,7 +144,7 @@ if HTOP_DARWIN AM_LDFLAGS += -framework IOKit -framework CoreFoundation myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \ darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \ -$(zfs_platform_sources) +zfs/ZfsArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c myhtopplatheaders = $(darwin_platform_headers) endif diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 267e8e94..122e0188 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -9,6 +9,8 @@ in the source distribution for its full text. #include "DarwinProcess.h" #include "DarwinProcessList.h" #include "CRT.h" +#include "zfs/ZfsArcStats.h" +#include "zfs/openzfs_sysctl.h" #include #include @@ -69,27 +71,11 @@ typedef struct DarwinProcessList_ { uint64_t user_threads; uint64_t global_diff; - int zfsArcEnabled; - unsigned long long int zfsArcMax; - unsigned long long int zfsArcSize; - 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; - + ZfsArcStats zfs; } DarwinProcessList; }*/ -static int MIB_kstat_zfs_misc_arcstats_c_max[5]; -static int MIB_kstat_zfs_misc_arcstats_size[5]; -static int MIB_kstat_zfs_misc_arcstats_mfu_size[5]; -static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; -static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; -static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; -static int MIB_kstat_zfs_misc_arcstats_other_size[5]; - void ProcessList_getHostInfo(host_basic_info_data_t *p) { mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT; @@ -150,48 +136,6 @@ struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) { return processes; } -static inline void DarwinProcessList_scanZfsArcstats(DarwinProcessList* dpl) { - size_t len; - - if (dpl->zfsArcEnabled) { - len = sizeof(dpl->zfsArcSize); - sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(dpl->zfsArcSize), &len , NULL, 0); - /* TODO: adjust reported memory in use to move ARC from wired to inactive - Like: - // In bytes - dpl->vm_stats.wire_count -= dpl->zfsArcSize / vm_page_size; - dpl->vm_stats.inactive_count += dpl->zfsArcSize / vm_page_size; - // Would purgable_count be more true? - // Then convert to KB: - */ - dpl->zfsArcSize /= 1024; - - len = sizeof(dpl->zfsArcMax); - sysctl(MIB_kstat_zfs_misc_arcstats_c_max, 5, &(dpl->zfsArcMax), &len , NULL, 0); - dpl->zfsArcMax /= 1024; - - len = sizeof(dpl->zfsArcMFU); - sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(dpl->zfsArcMFU), &len , NULL, 0); - dpl->zfsArcMFU /= 1024; - - len = sizeof(dpl->zfsArcMRU); - sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(dpl->zfsArcMRU), &len , NULL, 0); - dpl->zfsArcMRU /= 1024; - - len = sizeof(dpl->zfsArcAnon); - sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(dpl->zfsArcAnon), &len , NULL, 0); - dpl->zfsArcAnon /= 1024; - - len = sizeof(dpl->zfsArcHeader); - sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(dpl->zfsArcHeader), &len , NULL, 0); - dpl->zfsArcHeader /= 1024; - - len = sizeof(dpl->zfsArcOther); - sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(dpl->zfsArcOther), &len , NULL, 0); - dpl->zfsArcOther /= 1024; - } -} - ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { size_t len; DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList)); @@ -207,22 +151,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui ProcessList_getVMStats(&this->vm_stats); /* Initialize the ZFS kstats, if zfs.kext loaded */ - len = sizeof(this->zfsArcSize); - if (sysctlbyname("kstat.zfs.misc.arcstats.size", &this->zfsArcSize, &len, - NULL, 0) == 0 && this->zfsArcSize != 0) { - this->zfsArcEnabled = 1; - - len = 5; - sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.c_max", MIB_kstat_zfs_misc_arcstats_c_max, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); - } else { - this->zfsArcEnabled = 0; - } + this->zfs.enabled = openzfs_sysctl_init(); + openzfs_sysctl_updateArcStats(&this->zfs); this->super.kernelThreads = 0; this->super.userlandThreads = 0; @@ -252,7 +182,7 @@ void ProcessList_goThroughEntries(ProcessList* super) { dpl->prev_load = dpl->curr_load; ProcessList_allocateCPULoadInfo(&dpl->curr_load); ProcessList_getVMStats(&dpl->vm_stats); - DarwinProcessList_scanZfsArcstats(dpl); + openzfs_sysctl_updateArcStats(&dpl->zfs); /* Get the time difference */ dpl->global_diff = 0; diff --git a/darwin/DarwinProcessList.h b/darwin/DarwinProcessList.h index 6686d05c..73fbd34f 100644 --- a/darwin/DarwinProcessList.h +++ b/darwin/DarwinProcessList.h @@ -21,6 +21,7 @@ negative value if more than the installed version int CompareKernelVersion(short int major, short int minor, short int component); #include "ProcessList.h" +#include "zfs/ZfsArcStats.h" #include #include @@ -35,15 +36,7 @@ typedef struct DarwinProcessList_ { uint64_t user_threads; uint64_t global_diff; - int zfsArcEnabled; - unsigned long long int zfsArcMax; - unsigned long long int zfsArcSize; - 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; - + ZfsArcStats zfs; } DarwinProcessList; diff --git a/darwin/Platform.c b/darwin/Platform.c index 52d60a9b..8fbb9c93 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -246,18 +246,18 @@ void Platform_setSwapValues(Meter* mtr) { void Platform_setZfsArcValues(Meter* this) { DarwinProcessList* dpl = (DarwinProcessList*) this->pl; - this->total = dpl->zfsArcMax; - this->values[0] = dpl->zfsArcMFU; - this->values[1] = dpl->zfsArcMRU; - this->values[2] = dpl->zfsArcAnon; - this->values[3] = dpl->zfsArcHeader; - this->values[4] = dpl->zfsArcOther; + this->total = dpl->zfs.max; + this->values[0] = dpl->zfs.MFU; + this->values[1] = dpl->zfs.MRU; + this->values[2] = dpl->zfs.anon; + this->values[3] = dpl->zfs.header; + this->values[4] = dpl->zfs.other; // "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] = dpl->zfsArcSize; + this->values[5] = dpl->zfs.size; } char* Platform_getProcessEnv(pid_t pid) { diff --git a/darwin/Platform.h b/darwin/Platform.h index 4acda2c4..f8360775 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -48,7 +48,7 @@ void Platform_setMemoryValues(Meter* mtr); void Platform_setSwapValues(Meter* mtr); -void Platform_setZfsArcValues(Meter* mtr); +void Platform_setZfsArcValues(Meter* this); char* Platform_getProcessEnv(pid_t pid); diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 94cbaa19..1cbfdaab 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -8,6 +8,8 @@ in the source distribution for its full text. #include "ProcessList.h" #include "FreeBSDProcessList.h" #include "FreeBSDProcess.h" +#include "zfs/ZfsArcStats.h" +#include "zfs/openzfs_sysctl.h" #include #include @@ -21,6 +23,8 @@ in the source distribution for its full text. /*{ +#include "zfs/ZfsArcStats.h" + #include #include #include @@ -45,20 +49,12 @@ typedef struct FreeBSDProcessList_ { ProcessList super; kvm_t* kd; - int zfsArcEnabled; - unsigned long long int memWire; unsigned long long int memActive; unsigned long long int memInactive; unsigned long long int memFree; - 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; + ZfsArcStats zfs; CPUData* cpus; @@ -86,14 +82,6 @@ static int MIB_vm_stats_vm_v_free_count[4]; static int MIB_vfs_bufspace[2]; -static int MIB_kstat_zfs_misc_arcstats_size[5]; -static int MIB_vfs_zfs_arc_max[3]; -static int MIB_kstat_zfs_misc_arcstats_mfu_size[5]; -static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; -static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; -static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; -static int MIB_kstat_zfs_misc_arcstats_other_size[5]; - static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; static int kernelFScale; @@ -130,25 +118,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len); - len = sizeof(fpl->memZfsArc); - if (sysctlbyname("kstat.zfs.misc.arcstats.size", &fpl->memZfsArc, &len, - NULL, 0) == 0 && fpl->memZfsArc != 0) { - len = 5; sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); - fpl->zfsArcEnabled = 1; - - len = 3; - sysctlnametomib("vfs.zfs.arc_max", MIB_vfs_zfs_arc_max, &len); - - len = 5; - sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); - sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); - } else { - fpl->zfsArcEnabled = 0; - } - + fpl->zfs.enabled = openzfs_sysctl_init(); + openzfs_sysctl_updateArcStats(&fpl->zfs); int smp = 0; len = sizeof(smp); @@ -339,36 +310,9 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0); pl->cachedMem *= pageSizeKb; - if (fpl->zfsArcEnabled) { - len = sizeof(fpl->memZfsArc); - sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(fpl->memZfsArc), &len , NULL, 0); - fpl->memZfsArc /= 1024; - fpl->memWire -= fpl->memZfsArc; - pl->cachedMem += fpl->memZfsArc; - - len = sizeof(fpl->zfsArcMax); - sysctl(MIB_vfs_zfs_arc_max, 3, &(fpl->zfsArcMax), &len , NULL, 0); - fpl->zfsArcMax /= 1024; - - len = sizeof(fpl->zfsArcMFU); - sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(fpl->zfsArcMFU), &len , NULL, 0); - fpl->zfsArcMFU /= 1024; - - len = sizeof(fpl->zfsArcMRU); - sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(fpl->zfsArcMRU), &len , NULL, 0); - fpl->zfsArcMRU /= 1024; - - len = sizeof(fpl->zfsArcAnon); - sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(fpl->zfsArcAnon), &len , NULL, 0); - fpl->zfsArcAnon /= 1024; - - len = sizeof(fpl->zfsArcHeader); - sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(fpl->zfsArcHeader), &len , NULL, 0); - fpl->zfsArcHeader /= 1024; - - len = sizeof(fpl->zfsArcOther); - sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(fpl->zfsArcOther), &len , NULL, 0); - fpl->zfsArcOther /= 1024; + if (fpl->zfs.enabled) { + fpl->memWire -= fpl->zfs.size; + pl->cachedMem += fpl->zfs.size; } pl->usedMem = fpl->memActive + fpl->memWire; @@ -466,6 +410,7 @@ void ProcessList_goThroughEntries(ProcessList* this) { bool hideKernelThreads = settings->hideKernelThreads; bool hideUserlandThreads = settings->hideUserlandThreads; + openzfs_sysctl_updateArcStats(&fpl->zfs); FreeBSDProcessList_scanMemoryInfo(this); FreeBSDProcessList_scanCPUTime(this); diff --git a/freebsd/FreeBSDProcessList.h b/freebsd/FreeBSDProcessList.h index cf96a702..7c1b7ad4 100644 --- a/freebsd/FreeBSDProcessList.h +++ b/freebsd/FreeBSDProcessList.h @@ -10,6 +10,8 @@ in the source distribution for its full text. */ +#include "zfs/ZfsArcStats.h" + #include #include #include @@ -34,20 +36,12 @@ typedef struct FreeBSDProcessList_ { ProcessList super; kvm_t* kd; - int zfsArcEnabled; - unsigned long long int memWire; unsigned long long int memActive; unsigned long long int memInactive; unsigned long long int memFree; - 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; + ZfsArcStats zfs; CPUData* cpus; diff --git a/freebsd/Platform.c b/freebsd/Platform.c index d8d2ed06..05c0e922 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -202,18 +202,18 @@ void Platform_setSwapValues(Meter* this) { void Platform_setZfsArcValues(Meter* this) { FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl; - this->total = fpl->zfsArcMax; - this->values[0] = fpl->zfsArcMFU; - this->values[1] = fpl->zfsArcMRU; - this->values[2] = fpl->zfsArcAnon; - this->values[3] = fpl->zfsArcHeader; - this->values[4] = fpl->zfsArcOther; + this->total = fpl->zfs.max; + this->values[0] = fpl->zfs.MFU; + this->values[1] = fpl->zfs.MRU; + this->values[2] = fpl->zfs.anon; + this->values[3] = fpl->zfs.header; + this->values[4] = fpl->zfs.other; // "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] = fpl->memZfsArc; + this->values[5] = fpl->zfs.size; } void Platform_setTasksValues(Meter* this) { diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 4d19185c..3e889104 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -46,6 +46,7 @@ in the source distribution for its full text. /*{ #include "ProcessList.h" +#include "zfs/ZfsArcStats.h" extern long long btime; @@ -95,14 +96,7 @@ typedef struct LinuxProcessList_ { 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; + ZfsArcStats zfs; } LinuxProcessList; #ifndef PROCDIR @@ -984,7 +978,7 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { FILE* file = fopen(PROCARCSTATSFILE, "r"); if (file == NULL) { - lpl->zfsArcEnabled = 0; + lpl->zfs.enabled = 0; return; } char buffer[128]; @@ -992,13 +986,13 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { #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); + tryRead("c_max", &lpl->zfs.max); break; case 's': - tryRead("size", &lpl->memZfsArc); + tryRead("size", &lpl->zfs.size); break; case 'h': - tryRead("hdr_size", &lpl->zfsArcHeader); + tryRead("hdr_size", &lpl->zfs.header); break; case 'd': tryRead("dbuf_size", &dbufSize); @@ -1008,25 +1002,25 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { tryRead("bonus_size", &bonusSize); break; case 'a': - tryRead("anon_size", &lpl->zfsArcAnon); + tryRead("anon_size", &lpl->zfs.anon); break; case 'm': - tryRead("mfu_size", &lpl->zfsArcMFU); - tryRead("mru_size", &lpl->zfsArcMRU); + tryRead("mfu_size", &lpl->zfs.MFU); + tryRead("mru_size", &lpl->zfs.MRU); 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; + lpl->zfs.enabled = (lpl->zfs.size > 0 ? 1 : 0); + lpl->zfs.size /= 1024; + lpl->zfs.max /= 1024; + lpl->zfs.MFU /= 1024; + lpl->zfs.MRU /= 1024; + lpl->zfs.anon /= 1024; + lpl->zfs.header /= 1024; + lpl->zfs.other = (dbufSize + dnodeSize + bonusSize) / 1024; } static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) { diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h index 749231e1..353fe603 100644 --- a/linux/LinuxProcessList.h +++ b/linux/LinuxProcessList.h @@ -19,6 +19,7 @@ in the source distribution for its full text. #include "ProcessList.h" +#include "zfs/ZfsArcStats.h" extern long long btime; @@ -68,14 +69,7 @@ typedef struct LinuxProcessList_ { 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; + ZfsArcStats zfs; } LinuxProcessList; #ifndef PROCDIR diff --git a/linux/Platform.c b/linux/Platform.c index 4e73c61e..e2a3c6d3 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -218,18 +218,18 @@ void Platform_setSwapValues(Meter* this) { 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; + this->total = lpl->zfs.max; + this->values[0] = lpl->zfs.MFU; + this->values[1] = lpl->zfs.MRU; + this->values[2] = lpl->zfs.anon; + this->values[3] = lpl->zfs.header; + this->values[4] = lpl->zfs.other; // "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; + this->values[5] = lpl->zfs.size; } char* Platform_getProcessEnv(pid_t pid) { diff --git a/zfs/ZfsArcStats.c b/zfs/ZfsArcStats.c new file mode 100644 index 00000000..c33076a4 --- /dev/null +++ b/zfs/ZfsArcStats.c @@ -0,0 +1,19 @@ +/* +htop - ZfsArcStats.c +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +/*{ +typedef struct ZfsArcStats_ { + int enabled; + unsigned long long int max; + unsigned long long int size; + unsigned long long int MFU; + unsigned long long int MRU; + unsigned long long int anon; + unsigned long long int header; + unsigned long long int other; +} ZfsArcStats; +}*/ diff --git a/zfs/ZfsArcStats.h b/zfs/ZfsArcStats.h new file mode 100644 index 00000000..3697af23 --- /dev/null +++ b/zfs/ZfsArcStats.h @@ -0,0 +1,23 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_ZfsArcStats +#define HEADER_ZfsArcStats +/* +htop - ZfsArcStats.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +typedef struct ZfsArcStats_ { + int enabled; + unsigned long long int max; + unsigned long long int size; + unsigned long long int MFU; + unsigned long long int MRU; + unsigned long long int anon; + unsigned long long int header; + unsigned long long int other; +} ZfsArcStats; + +#endif diff --git a/zfs/openzfs_sysctl.c b/zfs/openzfs_sysctl.c new file mode 100644 index 00000000..ce48f233 --- /dev/null +++ b/zfs/openzfs_sysctl.c @@ -0,0 +1,81 @@ +/* +htop - zfs/openzfs_sysctl.c +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "zfs/openzfs_sysctl.h" +#include "zfs/ZfsArcStats.h" + +#include +#include +#include +#include + +static int MIB_kstat_zfs_misc_arcstats_size[5]; +static int MIB_kstat_zfs_misc_arcstats_c_max[5]; +static int MIB_kstat_zfs_misc_arcstats_mfu_size[5]; +static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; +static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; +static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; +static int MIB_kstat_zfs_misc_arcstats_other_size[5]; + +/*{ +#include "zfs/ZfsArcStats.h" +}*/ + +int openzfs_sysctl_init() { + size_t len; + unsigned long long int arcSize; + + len = sizeof(arcSize); + if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arcSize, &len, + NULL, 0) == 0 && arcSize != 0) { + len = 5; sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); + + sysctlnametomib("kstat.zfs.misc.arcstats.c_max", MIB_kstat_zfs_misc_arcstats_c_max, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.mfu_size", MIB_kstat_zfs_misc_arcstats_mfu_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.mru_size", MIB_kstat_zfs_misc_arcstats_mru_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); + sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); + return 1; + } else { + return 0; + } +} + +void openzfs_sysctl_updateArcStats(ZfsArcStats *stats) { + size_t len; + + if (stats->enabled) { + len = sizeof(stats->size); + sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(stats->size), &len , NULL, 0); + stats->size /= 1024; + + len = sizeof(stats->max); + sysctl(MIB_kstat_zfs_misc_arcstats_c_max, 5, &(stats->max), &len , NULL, 0); + stats->max /= 1024; + + len = sizeof(stats->MFU); + sysctl(MIB_kstat_zfs_misc_arcstats_mfu_size, 5, &(stats->MFU), &len , NULL, 0); + stats->MFU /= 1024; + + len = sizeof(stats->MRU); + sysctl(MIB_kstat_zfs_misc_arcstats_mru_size, 5, &(stats->MRU), &len , NULL, 0); + stats->MRU /= 1024; + + len = sizeof(stats->anon); + sysctl(MIB_kstat_zfs_misc_arcstats_anon_size, 5, &(stats->anon), &len , NULL, 0); + stats->anon /= 1024; + + len = sizeof(stats->header); + sysctl(MIB_kstat_zfs_misc_arcstats_hdr_size, 5, &(stats->header), &len , NULL, 0); + stats->header /= 1024; + + len = sizeof(stats->other); + sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(stats->other), &len , NULL, 0); + stats->other /= 1024; + } +} diff --git a/zfs/openzfs_sysctl.h b/zfs/openzfs_sysctl.h new file mode 100644 index 00000000..7c04bd79 --- /dev/null +++ b/zfs/openzfs_sysctl.h @@ -0,0 +1,18 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_openzfs +#define HEADER_openzfs +/* +htop - zfs/openzfs_sysctl.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "zfs/ZfsArcStats.h" + +int openzfs_sysctl_init(); + +void openzfs_sysctl_updateArcStats(ZfsArcStats *stats); + +#endif From ff6914e4ad4b78749bcee5471a33ef206b0a7d03 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Mon, 8 Jul 2019 02:43:39 +0000 Subject: [PATCH 6/9] ZFS arcstats for Solaris --- Makefile.am | 7 +++++-- solaris/Platform.c | 19 ++++++++++++++++++ solaris/Platform.h | 2 ++ solaris/SolarisProcessList.c | 37 ++++++++++++++++++++++++++++++++++++ solaris/SolarisProcessList.h | 3 +++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5eee6315..204a8b7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -157,14 +157,17 @@ solaris_platform_headers = \ solaris/SolarisProcess.h \ solaris/SolarisProcessList.h \ solaris/SolarisCRT.h \ - solaris/Battery.h + solaris/Battery.h \ + zfs/ZfsArcMeter.h \ + zfs/ZfsArcStats.h all_platform_headers += $(solaris_platform_headers) if HTOP_SOLARIS myhtopplatsources = solaris/Platform.c \ solaris/SolarisProcess.c solaris/SolarisProcessList.c \ -solaris/SolarisCRT.c solaris/Battery.c +solaris/SolarisCRT.c solaris/Battery.c \ +zfs/ZfsArcMeter.c zfs/ZfsArcStats.c myhtopplatheaders = $(solaris_platform_headers) endif diff --git a/solaris/Platform.c b/solaris/Platform.c index a29fcb47..8084d1fd 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -17,6 +17,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "UptimeMeter.h" +#include "zfs/ZfsArcMeter.h" #include "SolarisProcess.h" #include "SolarisProcessList.h" @@ -122,6 +123,7 @@ MeterClass* Platform_meterTypes[] = { &RightCPUsMeter_class, &LeftCPUs2Meter_class, &RightCPUs2Meter_class, + &ZfsArcMeter_class, &BlankMeter_class, NULL }; @@ -220,6 +222,23 @@ void Platform_setSwapValues(Meter* this) { this->values[0] = pl->usedSwap; } +void Platform_setZfsArcValues(Meter* this) { + SolarisProcessList* spl = (SolarisProcessList*) this->pl; + + this->total = spl->zfs.max; + this->values[0] = spl->zfs.MFU; + this->values[1] = spl->zfs.MRU; + this->values[2] = spl->zfs.anon; + this->values[3] = spl->zfs.header; + this->values[4] = spl->zfs.other; + + // "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] = spl->zfs.size; +} + static int Platform_buildenv(void *accum, struct ps_prochandle *Phandle, uintptr_t addr, const char *str) { envAccum *accump = accum; (void) Phandle; diff --git a/solaris/Platform.h b/solaris/Platform.h index f961b913..62757ff7 100644 --- a/solaris/Platform.h +++ b/solaris/Platform.h @@ -60,6 +60,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/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c index 2c681852..b6bc6f5d 100644 --- a/solaris/SolarisProcessList.c +++ b/solaris/SolarisProcessList.c @@ -27,6 +27,8 @@ in the source distribution for its full text. /*{ +#include "zfs/ZfsArcStats.h" + #include #include #include @@ -55,6 +57,7 @@ typedef struct SolarisProcessList_ { ProcessList super; kstat_ctl_t* kd; CPUData* cpus; + ZfsArcStats zfs; } SolarisProcessList; }*/ @@ -230,6 +233,39 @@ static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) { pl->usedSwap = pl->totalSwap - (totalfree * PAGE_SIZE_KB); } +static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) { + SolarisProcessList* spl = (SolarisProcessList*) pl; + kstat_t *arcstats = NULL; + int ksrphyserr = -1; + kstat_named_t *cur_kstat = NULL; + + if (spl->kd != NULL) { arcstats = kstat_lookup(spl->kd,"zfs",0,"arcstats"); } + if (arcstats != NULL) { ksrphyserr = kstat_read(spl->kd,arcstats,NULL); } + if (ksrphyserr != -1) { + cur_kstat = kstat_data_lookup( arcstats, "size" ); + spl->zfs.size = cur_kstat->value.ui64 / 1024; + spl->zfs.enabled = spl->zfs.size > 0 ? 1 : 0; + + cur_kstat = kstat_data_lookup( arcstats, "c_max" ); + spl->zfs.max = cur_kstat->value.ui64 / 1024; + + cur_kstat = kstat_data_lookup( arcstats, "mfu_size" ); + spl->zfs.MFU = cur_kstat->value.ui64 / 1024; + + cur_kstat = kstat_data_lookup( arcstats, "mru_size" ); + spl->zfs.MRU = cur_kstat->value.ui64 / 1024; + + cur_kstat = kstat_data_lookup( arcstats, "anon_size" ); + spl->zfs.anon = cur_kstat->value.ui64 / 1024; + + cur_kstat = kstat_data_lookup( arcstats, "hdr_size" ); + spl->zfs.header = cur_kstat->value.ui64 / 1024; + + cur_kstat = kstat_data_lookup( arcstats, "other_size" ); + spl->zfs.other = cur_kstat->value.ui64 / 1024; + } +} + void ProcessList_delete(ProcessList* pl) { SolarisProcessList* spl = (SolarisProcessList*) pl; ProcessList_done(pl); @@ -367,6 +403,7 @@ int SolarisProcessList_walkproc(psinfo_t *_psinfo, lwpsinfo_t *_lwpsinfo, void * void ProcessList_goThroughEntries(ProcessList* this) { SolarisProcessList_scanCPUTime(this); SolarisProcessList_scanMemoryInfo(this); + SolarisProcessList_scanZfsArcstats(this); this->kernelThreads = 1; proc_walk(&SolarisProcessList_walkproc, this, PR_WALK_LWP); } diff --git a/solaris/SolarisProcessList.h b/solaris/SolarisProcessList.h index a5f2fbc2..26bf4491 100644 --- a/solaris/SolarisProcessList.h +++ b/solaris/SolarisProcessList.h @@ -13,6 +13,8 @@ in the source distribution for its full text. #define MAXCMDLINE 255 +#include "zfs/ZfsArcStats.h" + #include #include #include @@ -41,6 +43,7 @@ typedef struct SolarisProcessList_ { ProcessList super; kstat_ctl_t* kd; CPUData* cpus; + ZfsArcStats zfs; } SolarisProcessList; From e450b586368750e771746ef3e2f5a070962dfd28 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Tue, 3 Sep 2019 18:21:33 +0000 Subject: [PATCH 7/9] Refactor openzfs_sysctl_init() and ZfsArcMeter... openzfs_sysctl_init() now returns void instead of int. The ZfsArcStats->enabled flag is set inside the init function now, instead of having to be set from its return value. Preparation for more flag setting in Compressed ARC commit. ZfsArcMeter_readStats() added and all Meter->values[] setting moved to it, eliminating duplicated code in {darwin,freebsd,linux,solaris}/Platform.c. --- darwin/DarwinProcessList.c | 2 +- darwin/Platform.c | 13 +------------ freebsd/FreeBSDProcessList.c | 2 +- freebsd/Platform.c | 13 +------------ linux/Platform.c | 13 +------------ solaris/Platform.c | 13 +------------ zfs/ZfsArcMeter.c | 18 ++++++++++++++++++ zfs/ZfsArcMeter.h | 4 ++++ zfs/openzfs_sysctl.c | 6 +++--- zfs/openzfs_sysctl.h | 6 +++--- 10 files changed, 34 insertions(+), 56 deletions(-) diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 122e0188..9b4ba119 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -151,7 +151,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui ProcessList_getVMStats(&this->vm_stats); /* Initialize the ZFS kstats, if zfs.kext loaded */ - this->zfs.enabled = openzfs_sysctl_init(); + openzfs_sysctl_init(&this->zfs); openzfs_sysctl_updateArcStats(&this->zfs); this->super.kernelThreads = 0; diff --git a/darwin/Platform.c b/darwin/Platform.c index 8fbb9c93..f9f09b5a 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -246,18 +246,7 @@ void Platform_setSwapValues(Meter* mtr) { void Platform_setZfsArcValues(Meter* this) { DarwinProcessList* dpl = (DarwinProcessList*) this->pl; - this->total = dpl->zfs.max; - this->values[0] = dpl->zfs.MFU; - this->values[1] = dpl->zfs.MRU; - this->values[2] = dpl->zfs.anon; - this->values[3] = dpl->zfs.header; - this->values[4] = dpl->zfs.other; - - // "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] = dpl->zfs.size; + ZfsArcMeter_readStats(this, &(dpl->zfs)); } char* Platform_getProcessEnv(pid_t pid) { diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 1cbfdaab..fd694198 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -118,7 +118,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len); - fpl->zfs.enabled = openzfs_sysctl_init(); + openzfs_sysctl_init(&fpl->zfs); openzfs_sysctl_updateArcStats(&fpl->zfs); int smp = 0; diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 05c0e922..b08a508e 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -202,18 +202,7 @@ void Platform_setSwapValues(Meter* this) { void Platform_setZfsArcValues(Meter* this) { FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl; - this->total = fpl->zfs.max; - this->values[0] = fpl->zfs.MFU; - this->values[1] = fpl->zfs.MRU; - this->values[2] = fpl->zfs.anon; - this->values[3] = fpl->zfs.header; - this->values[4] = fpl->zfs.other; - - // "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] = fpl->zfs.size; + ZfsArcMeter_readStats(this, &(fpl->zfs)); } void Platform_setTasksValues(Meter* this) { diff --git a/linux/Platform.c b/linux/Platform.c index e2a3c6d3..69f66880 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -218,18 +218,7 @@ void Platform_setSwapValues(Meter* this) { void Platform_setZfsArcValues(Meter* this) { LinuxProcessList* lpl = (LinuxProcessList*) this->pl; - this->total = lpl->zfs.max; - this->values[0] = lpl->zfs.MFU; - this->values[1] = lpl->zfs.MRU; - this->values[2] = lpl->zfs.anon; - this->values[3] = lpl->zfs.header; - this->values[4] = lpl->zfs.other; - - // "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->zfs.size; + ZfsArcMeter_readStats(this, &(lpl->zfs)); } char* Platform_getProcessEnv(pid_t pid) { diff --git a/solaris/Platform.c b/solaris/Platform.c index 8084d1fd..74ae14ec 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -225,18 +225,7 @@ void Platform_setSwapValues(Meter* this) { void Platform_setZfsArcValues(Meter* this) { SolarisProcessList* spl = (SolarisProcessList*) this->pl; - this->total = spl->zfs.max; - this->values[0] = spl->zfs.MFU; - this->values[1] = spl->zfs.MRU; - this->values[2] = spl->zfs.anon; - this->values[3] = spl->zfs.header; - this->values[4] = spl->zfs.other; - - // "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] = spl->zfs.size; + ZfsArcMeter_readStats(this, &(spl->zfs)); } static int Platform_buildenv(void *accum, struct ps_prochandle *Phandle, uintptr_t addr, const char *str) { diff --git a/zfs/ZfsArcMeter.c b/zfs/ZfsArcMeter.c index ebd80992..9f7028bc 100644 --- a/zfs/ZfsArcMeter.c +++ b/zfs/ZfsArcMeter.c @@ -6,6 +6,7 @@ in the source distribution for its full text. */ #include "ZfsArcMeter.h" +#include "ZfsArcStats.h" #include "CRT.h" #include "Platform.h" @@ -17,6 +18,8 @@ in the source distribution for its full text. #include /*{ +#include "ZfsArcStats.h" + #include "Meter.h" }*/ @@ -24,6 +27,21 @@ int ZfsArcMeter_attributes[] = { ZFS_MFU, ZFS_MRU, ZFS_ANON, ZFS_HEADER, ZFS_OTHER }; +void ZfsArcMeter_readStats(Meter* this, ZfsArcStats* stats) { + this->total = stats->max; + this->values[0] = stats->MFU; + this->values[1] = stats->MRU; + this->values[2] = stats->anon; + this->values[3] = stats->header; + this->values[4] = stats->other; + + // "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] = stats->size; +} + static void ZfsArcMeter_updateValues(Meter* this, char* buffer, int size) { int written; Platform_setZfsArcValues(this); diff --git a/zfs/ZfsArcMeter.h b/zfs/ZfsArcMeter.h index b89be223..c52083df 100644 --- a/zfs/ZfsArcMeter.h +++ b/zfs/ZfsArcMeter.h @@ -9,10 +9,14 @@ Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ +#include "ZfsArcStats.h" + #include "Meter.h" extern int ZfsArcMeter_attributes[]; +void ZfsArcMeter_readStats(Meter* this, ZfsArcStats* stats); + extern MeterClass ZfsArcMeter_class; #endif diff --git a/zfs/openzfs_sysctl.c b/zfs/openzfs_sysctl.c index ce48f233..ceee4d10 100644 --- a/zfs/openzfs_sysctl.c +++ b/zfs/openzfs_sysctl.c @@ -25,13 +25,14 @@ static int MIB_kstat_zfs_misc_arcstats_other_size[5]; #include "zfs/ZfsArcStats.h" }*/ -int openzfs_sysctl_init() { +void openzfs_sysctl_init(ZfsArcStats *stats) { size_t len; unsigned long long int arcSize; len = sizeof(arcSize); if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arcSize, &len, NULL, 0) == 0 && arcSize != 0) { + stats->enabled = 1; len = 5; sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); sysctlnametomib("kstat.zfs.misc.arcstats.c_max", MIB_kstat_zfs_misc_arcstats_c_max, &len); @@ -40,9 +41,8 @@ int openzfs_sysctl_init() { sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); - return 1; } else { - return 0; + stats->enabled = 0; } } diff --git a/zfs/openzfs_sysctl.h b/zfs/openzfs_sysctl.h index 7c04bd79..6e44ac3b 100644 --- a/zfs/openzfs_sysctl.h +++ b/zfs/openzfs_sysctl.h @@ -1,7 +1,7 @@ /* Do not edit this file. It was automatically generated. */ -#ifndef HEADER_openzfs -#define HEADER_openzfs +#ifndef HEADER_openzfs_sysctl +#define HEADER_openzfs_sysctl /* htop - zfs/openzfs_sysctl.h (C) 2014 Hisham H. Muhammad @@ -11,7 +11,7 @@ in the source distribution for its full text. #include "zfs/ZfsArcStats.h" -int openzfs_sysctl_init(); +void openzfs_sysctl_init(ZfsArcStats *stats); void openzfs_sysctl_updateArcStats(ZfsArcStats *stats); From 613556faebd16325da8c9057c81f39a2410d803f Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Tue, 3 Sep 2019 18:26:02 +0000 Subject: [PATCH 8/9] Support for ZFS Compressed ARC statistics --- CRT.c | 14 ++++++ CRT.h | 2 + Makefile.am | 12 +++-- darwin/Platform.c | 8 ++++ darwin/Platform.h | 2 + freebsd/Platform.c | 8 ++++ freebsd/Platform.h | 2 + linux/LinuxProcessList.c | 10 +++++ linux/Platform.c | 7 +++ linux/Platform.h | 2 + solaris/Platform.c | 8 ++++ solaris/Platform.h | 2 + solaris/SolarisProcessList.c | 10 +++++ zfs/ZfsArcStats.c | 3 ++ zfs/ZfsArcStats.h | 3 ++ zfs/ZfsCompressedArcMeter.c | 86 ++++++++++++++++++++++++++++++++++++ zfs/ZfsCompressedArcMeter.h | 22 +++++++++ zfs/openzfs_sysctl.c | 18 ++++++++ 18 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 zfs/ZfsCompressedArcMeter.c create mode 100644 zfs/ZfsCompressedArcMeter.h diff --git a/CRT.c b/CRT.c index b9017aa4..cb36b6c0 100644 --- a/CRT.c +++ b/CRT.c @@ -133,6 +133,8 @@ typedef enum ColorElements_ { ZFS_ANON, ZFS_HEADER, ZFS_OTHER, + ZFS_COMPRESSED, + ZFS_RATIO, LAST_COLORELEMENT } ColorElements; @@ -242,6 +244,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = ColorPair(Magenta,Black), [ZFS_HEADER] = ColorPair(Cyan,Black), [ZFS_OTHER] = ColorPair(Magenta,Black), + [ZFS_COMPRESSED] = ColorPair(Blue,Black), + [ZFS_RATIO] = ColorPair(Magenta,Black), }, [COLORSCHEME_MONOCHROME] = { [RESET_COLOR] = A_NORMAL, @@ -306,6 +310,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = A_DIM, [ZFS_HEADER] = A_BOLD, [ZFS_OTHER] = A_DIM, + [ZFS_COMPRESSED] = A_BOLD, + [ZFS_RATIO] = A_BOLD, }, [COLORSCHEME_BLACKONWHITE] = { [RESET_COLOR] = ColorPair(Black,White), @@ -370,6 +376,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = ColorPair(Magenta,White), [ZFS_HEADER] = ColorPair(Yellow,White), [ZFS_OTHER] = ColorPair(Magenta,White), + [ZFS_COMPRESSED] = ColorPair(Cyan,White), + [ZFS_RATIO] = ColorPair(Magenta,White), }, [COLORSCHEME_LIGHTTERMINAL] = { [RESET_COLOR] = ColorPair(Black,Black), @@ -434,6 +442,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = A_BOLD | ColorPair(Magenta,Black), [ZFS_HEADER] = ColorPair(Black,Black), [ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Black), + [ZFS_COMPRESSED] = ColorPair(Cyan,Black), + [ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Black), }, [COLORSCHEME_MIDNIGHT] = { [RESET_COLOR] = ColorPair(White,Blue), @@ -498,6 +508,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = A_BOLD | ColorPair(Magenta,Blue), [ZFS_HEADER] = A_BOLD | ColorPair(Yellow,Blue), [ZFS_OTHER] = A_BOLD | ColorPair(Magenta,Blue), + [ZFS_COMPRESSED] = A_BOLD | ColorPair(White,Blue), + [ZFS_RATIO] = A_BOLD | ColorPair(Magenta,Blue), }, [COLORSCHEME_BLACKNIGHT] = { [RESET_COLOR] = ColorPair(Cyan,Black), @@ -562,6 +574,8 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [ZFS_ANON] = ColorPair(Magenta,Black), [ZFS_HEADER] = ColorPair(Yellow,Black), [ZFS_OTHER] = ColorPair(Magenta,Black), + [ZFS_COMPRESSED] = ColorPair(Blue,Black), + [ZFS_RATIO] = ColorPair(Magenta,Black), }, [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. }; diff --git a/CRT.h b/CRT.h index 2275349a..d9eba556 100644 --- a/CRT.h +++ b/CRT.h @@ -121,6 +121,8 @@ typedef enum ColorElements_ { ZFS_ANON, ZFS_HEADER, ZFS_OTHER, + ZFS_COMPRESSED, + ZFS_RATIO, LAST_COLORELEMENT } ColorElements; diff --git a/Makefile.am b/Makefile.am index 204a8b7d..2d159f02 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,6 +50,7 @@ linux_platform_headers = \ linux/LinuxCRT.h \ linux/Battery.h \ zfs/ZfsArcMeter.h \ + zfs/ZfsCompressedArcMeter.h \ zfs/ZfsArcStats.h all_platform_headers += $(linux_platform_headers) @@ -58,7 +59,7 @@ 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 \ -zfs/ZfsArcMeter.c zfs/ZfsArcStats.c +zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c myhtopplatheaders = $(linux_platform_headers) endif @@ -73,6 +74,7 @@ freebsd_platform_headers = \ freebsd/FreeBSDCRT.h \ freebsd/Battery.h \ zfs/ZfsArcMeter.h \ + zfs/ZfsCompressedArcMeter.h \ zfs/ZfsArcStats.h \ zfs/openzfs_sysctl.h @@ -81,7 +83,7 @@ all_platform_headers += $(freebsd_platform_headers) if HTOP_FREEBSD myhtopplatsources = freebsd/Platform.c freebsd/FreeBSDProcessList.c \ freebsd/FreeBSDProcess.c freebsd/FreeBSDCRT.c freebsd/Battery.c \ -zfs/ZfsArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c +zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c myhtopplatheaders = $(freebsd_platform_headers) endif @@ -135,6 +137,7 @@ darwin_platform_headers = \ darwin/DarwinCRT.h \ darwin/Battery.h \ zfs/ZfsArcMeter.h \ + zfs/ZfsCompressedArcMeter.h \ zfs/ZfsArcStats.h \ zfs/openzfs_sysctl.h @@ -144,7 +147,7 @@ if HTOP_DARWIN AM_LDFLAGS += -framework IOKit -framework CoreFoundation myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \ darwin/DarwinProcessList.c darwin/DarwinCRT.c darwin/Battery.c \ -zfs/ZfsArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c +zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c zfs/openzfs_sysctl.c myhtopplatheaders = $(darwin_platform_headers) endif @@ -159,6 +162,7 @@ solaris_platform_headers = \ solaris/SolarisCRT.h \ solaris/Battery.h \ zfs/ZfsArcMeter.h \ + zfs/ZfsCompressedArcMeter.h \ zfs/ZfsArcStats.h all_platform_headers += $(solaris_platform_headers) @@ -167,7 +171,7 @@ if HTOP_SOLARIS myhtopplatsources = solaris/Platform.c \ solaris/SolarisProcess.c solaris/SolarisProcessList.c \ solaris/SolarisCRT.c solaris/Battery.c \ -zfs/ZfsArcMeter.c zfs/ZfsArcStats.c +zfs/ZfsArcMeter.c zfs/ZfsCompressedArcMeter.c zfs/ZfsArcStats.c myhtopplatheaders = $(solaris_platform_headers) endif diff --git a/darwin/Platform.c b/darwin/Platform.c index f9f09b5a..286ff16b 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -16,6 +16,7 @@ in the source distribution for its full text. #include "HostnameMeter.h" #include "UptimeMeter.h" #include "zfs/ZfsArcMeter.h" +#include "zfs/ZfsCompressedArcMeter.h" #include "DarwinProcessList.h" #include @@ -119,6 +120,7 @@ MeterClass* Platform_meterTypes[] = { &LeftCPUs2Meter_class, &RightCPUs2Meter_class, &ZfsArcMeter_class, + &ZfsCompressedArcMeter_class, &BlankMeter_class, NULL }; @@ -249,6 +251,12 @@ void Platform_setZfsArcValues(Meter* this) { ZfsArcMeter_readStats(this, &(dpl->zfs)); } +void Platform_setZfsCompressedArcValues(Meter* this) { + DarwinProcessList* dpl = (DarwinProcessList*) this->pl; + + ZfsCompressedArcMeter_readStats(this, &(dpl->zfs)); +} + char* Platform_getProcessEnv(pid_t pid) { char* env = NULL; diff --git a/darwin/Platform.h b/darwin/Platform.h index f8360775..e17661d6 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -50,6 +50,8 @@ void Platform_setSwapValues(Meter* mtr); void Platform_setZfsArcValues(Meter* this); +void Platform_setZfsCompressedArcValues(Meter* this); + char* Platform_getProcessEnv(pid_t pid); #endif diff --git a/freebsd/Platform.c b/freebsd/Platform.c index b08a508e..0986a3dd 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -16,6 +16,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "zfs/ZfsArcMeter.h" +#include "zfs/ZfsCompressedArcMeter.h" #include "FreeBSDProcess.h" #include "FreeBSDProcessList.h" @@ -106,6 +107,7 @@ MeterClass* Platform_meterTypes[] = { &RightCPUs2Meter_class, &BlankMeter_class, &ZfsArcMeter_class, + &ZfsCompressedArcMeter_class, NULL }; @@ -205,6 +207,12 @@ void Platform_setZfsArcValues(Meter* this) { ZfsArcMeter_readStats(this, &(fpl->zfs)); } +void Platform_setZfsCompressedArcValues(Meter* this) { + FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl; + + ZfsCompressedArcMeter_readStats(this, &(fpl->zfs)); +} + void Platform_setTasksValues(Meter* this) { // TODO } diff --git a/freebsd/Platform.h b/freebsd/Platform.h index 3dc7ebf2..0268f2c6 100644 --- a/freebsd/Platform.h +++ b/freebsd/Platform.h @@ -46,6 +46,8 @@ void Platform_setSwapValues(Meter* this); void Platform_setZfsArcValues(Meter* this); +void Platform_setZfsCompressedArcValues(Meter* this); + void Platform_setTasksValues(Meter* this); char* Platform_getProcessEnv(pid_t pid); diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 3e889104..4596c3bc 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -984,9 +984,14 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { 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) + #define tryReadFlag(label, variable, flag) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %*2u %32llu", variable)) { flag = 1; break; } else { flag = 0; } } while(0) switch (buffer[0]) { case 'c': tryRead("c_max", &lpl->zfs.max); + tryReadFlag("compressed", &lpl->zfs.compressed, &lpl->zfs.isCompressed); + break; + case 'u': + tryRead("uncompressed", &lpl->zfs.uncompressed); break; case 's': tryRead("size", &lpl->zfs.size); @@ -1010,6 +1015,7 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { break; } #undef tryRead + #undef tryReadFlag } fclose(file); @@ -1021,6 +1027,10 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { lpl->zfs.anon /= 1024; lpl->zfs.header /= 1024; lpl->zfs.other = (dbufSize + dnodeSize + bonusSize) / 1024; + if ( lpl->zfs.isCompressed ) { + lpl->zfs.compressed /= 1024; + lpl->zfs.uncompressed /= 1024; + } } static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) { diff --git a/linux/Platform.c b/linux/Platform.c index 69f66880..f7088cf4 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -22,6 +22,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "zfs/ZfsArcMeter.h" +#include "zfs/ZfsCompressedArcMeter.h" #include "LinuxProcess.h" #include @@ -128,6 +129,7 @@ MeterClass* Platform_meterTypes[] = { &RightCPUs2Meter_class, &BlankMeter_class, &ZfsArcMeter_class, + &ZfsCompressedArcMeter_class, NULL }; @@ -221,6 +223,11 @@ void Platform_setZfsArcValues(Meter* this) { ZfsArcMeter_readStats(this, &(lpl->zfs)); } +void Platform_setZfsCompressedArcValues(Meter* this) { + LinuxProcessList* lpl = (LinuxProcessList*) this->pl; + + ZfsCompressedArcMeter_readStats(this, &(lpl->zfs)); +} 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 e775181e..5d85eb36 100644 --- a/linux/Platform.h +++ b/linux/Platform.h @@ -45,6 +45,8 @@ void Platform_setSwapValues(Meter* this); void Platform_setZfsArcValues(Meter* this); +void Platform_setZfsCompressedArcValues(Meter* this); + char* Platform_getProcessEnv(pid_t pid); #endif diff --git a/solaris/Platform.c b/solaris/Platform.c index 74ae14ec..7dcfe323 100644 --- a/solaris/Platform.c +++ b/solaris/Platform.c @@ -18,6 +18,7 @@ in the source distribution for its full text. #include "HostnameMeter.h" #include "UptimeMeter.h" #include "zfs/ZfsArcMeter.h" +#include "zfs/ZfsCompressedArcMeter.h" #include "SolarisProcess.h" #include "SolarisProcessList.h" @@ -124,6 +125,7 @@ MeterClass* Platform_meterTypes[] = { &LeftCPUs2Meter_class, &RightCPUs2Meter_class, &ZfsArcMeter_class, + &ZfsCompressedArcMeter_class, &BlankMeter_class, NULL }; @@ -228,6 +230,12 @@ void Platform_setZfsArcValues(Meter* this) { ZfsArcMeter_readStats(this, &(spl->zfs)); } +void Platform_setZfsCompressedArcValues(Meter* this) { + SolarisProcessList* spl = (SolarisProcessList*) this->pl; + + ZfsCompressedArcMeter_readStats(this, &(spl->zfs)); +} + static int Platform_buildenv(void *accum, struct ps_prochandle *Phandle, uintptr_t addr, const char *str) { envAccum *accump = accum; (void) Phandle; diff --git a/solaris/Platform.h b/solaris/Platform.h index 62757ff7..3b5aef86 100644 --- a/solaris/Platform.h +++ b/solaris/Platform.h @@ -62,6 +62,8 @@ void Platform_setSwapValues(Meter* this); void Platform_setZfsArcValues(Meter* this); +void Platform_setZfsCompressedArcValues(Meter* this); + char* Platform_getProcessEnv(pid_t pid); #endif diff --git a/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c index b6bc6f5d..d62ea1d4 100644 --- a/solaris/SolarisProcessList.c +++ b/solaris/SolarisProcessList.c @@ -263,6 +263,16 @@ static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) { cur_kstat = kstat_data_lookup( arcstats, "other_size" ); spl->zfs.other = cur_kstat->value.ui64 / 1024; + + if ((cur_kstat = kstat_data_lookup( arcstats, "compressed_size" )) != NULL) { + spl->zfs.compressed = cur_kstat->value.ui64 / 1024; + spl->zfs.isCompressed = 1; + + cur_kstat = kstat_data_lookup( arcstats, "uncompressed_size" ); + spl->zfs.uncompressed = cur_kstat->value.ui64 / 1024; + } else { + spl->zfs.isCompressed = 0; + } } } diff --git a/zfs/ZfsArcStats.c b/zfs/ZfsArcStats.c index c33076a4..1bfaf47d 100644 --- a/zfs/ZfsArcStats.c +++ b/zfs/ZfsArcStats.c @@ -8,6 +8,7 @@ in the source distribution for its full text. /*{ typedef struct ZfsArcStats_ { int enabled; + int isCompressed; unsigned long long int max; unsigned long long int size; unsigned long long int MFU; @@ -15,5 +16,7 @@ typedef struct ZfsArcStats_ { unsigned long long int anon; unsigned long long int header; unsigned long long int other; + unsigned long long int compressed; + unsigned long long int uncompressed; } ZfsArcStats; }*/ diff --git a/zfs/ZfsArcStats.h b/zfs/ZfsArcStats.h index 3697af23..ee5d0edd 100644 --- a/zfs/ZfsArcStats.h +++ b/zfs/ZfsArcStats.h @@ -11,6 +11,7 @@ in the source distribution for its full text. typedef struct ZfsArcStats_ { int enabled; + int isCompressed; unsigned long long int max; unsigned long long int size; unsigned long long int MFU; @@ -18,6 +19,8 @@ typedef struct ZfsArcStats_ { unsigned long long int anon; unsigned long long int header; unsigned long long int other; + unsigned long long int compressed; + unsigned long long int uncompressed; } ZfsArcStats; #endif diff --git a/zfs/ZfsCompressedArcMeter.c b/zfs/ZfsCompressedArcMeter.c new file mode 100644 index 00000000..ac3944d3 --- /dev/null +++ b/zfs/ZfsCompressedArcMeter.c @@ -0,0 +1,86 @@ +/* +htop - ZfsCompressedArcMeter.c +(C) 2004-2011 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "ZfsCompressedArcMeter.h" +#include "ZfsArcStats.h" + +#include "CRT.h" +#include "Platform.h" + +#include +#include +#include +#include +#include + +/*{ +#include "ZfsArcStats.h" + +#include "Meter.h" +}*/ + +int ZfsCompressedArcMeter_attributes[] = { + ZFS_COMPRESSED +}; + +void ZfsCompressedArcMeter_readStats(Meter* this, ZfsArcStats* stats) { + if ( stats->isCompressed ) { + this->total = stats->uncompressed; + this->values[0] = stats->compressed; + } else { + // For uncompressed ARC, report 1:1 ratio + this->total = stats->size; + this->values[0] = stats->size; + } +} + +static void ZfsCompressedArcMeter_printRatioString(Meter* this, char* buffer, int size) { + xSnprintf(buffer, size, "%.2f:1", this->total/this->values[0]); +} + +static void ZfsCompressedArcMeter_updateValues(Meter* this, char* buffer, int size) { + Platform_setZfsCompressedArcValues(this); + + ZfsCompressedArcMeter_printRatioString(this, buffer, size); +} + +static void ZfsCompressedArcMeter_display(Object* cast, RichString* out) { + char buffer[50]; + Meter* this = (Meter*)cast; + + if (this->values[0] > 0) { + Meter_humanUnit(buffer, this->total, 50); + RichString_append(out, CRT_colors[METER_VALUE], buffer); + RichString_append(out, CRT_colors[METER_TEXT], " Uncompressed, "); + Meter_humanUnit(buffer, this->values[0], 50); + RichString_append(out, CRT_colors[METER_VALUE], buffer); + RichString_append(out, CRT_colors[METER_TEXT], " Compressed, "); + ZfsCompressedArcMeter_printRatioString(this, buffer, 50); + RichString_append(out, CRT_colors[METER_VALUE], buffer); + RichString_append(out, CRT_colors[METER_TEXT], " Ratio"); + } else { + RichString_write(out, CRT_colors[METER_TEXT], " "); + RichString_append(out, CRT_colors[FAILED_SEARCH], "Compression Unavailable"); + } +} + +MeterClass ZfsCompressedArcMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete, + .display = ZfsCompressedArcMeter_display, + }, + .updateValues = ZfsCompressedArcMeter_updateValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = ZfsCompressedArcMeter_attributes, + .name = "ZFSCARC", + .uiName = "ZFS CARC", + .description = "ZFS CARC: Compressed ARC statistics", + .caption = "ARC: " +}; diff --git a/zfs/ZfsCompressedArcMeter.h b/zfs/ZfsCompressedArcMeter.h new file mode 100644 index 00000000..5afcc99e --- /dev/null +++ b/zfs/ZfsCompressedArcMeter.h @@ -0,0 +1,22 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_ZfsCompressedArcMeter +#define HEADER_ZfsCompressedArcMeter +/* +htop - ZfsCompressedArcMeter.h +(C) 2004-2011 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "ZfsArcStats.h" + +#include "Meter.h" + +extern int ZfsCompressedArcMeter_attributes[]; + +void ZfsCompressedArcMeter_readStats(Meter* this, ZfsArcStats* stats); + +extern MeterClass ZfsCompressedArcMeter_class; + +#endif diff --git a/zfs/openzfs_sysctl.c b/zfs/openzfs_sysctl.c index ceee4d10..c1ab2239 100644 --- a/zfs/openzfs_sysctl.c +++ b/zfs/openzfs_sysctl.c @@ -20,6 +20,8 @@ static int MIB_kstat_zfs_misc_arcstats_mru_size[5]; static int MIB_kstat_zfs_misc_arcstats_anon_size[5]; static int MIB_kstat_zfs_misc_arcstats_hdr_size[5]; static int MIB_kstat_zfs_misc_arcstats_other_size[5]; +static int MIB_kstat_zfs_misc_arcstats_compressed_size[5]; +static int MIB_kstat_zfs_misc_arcstats_uncompressed_size[5]; /*{ #include "zfs/ZfsArcStats.h" @@ -41,6 +43,12 @@ void openzfs_sysctl_init(ZfsArcStats *stats) { sysctlnametomib("kstat.zfs.misc.arcstats.anon_size", MIB_kstat_zfs_misc_arcstats_anon_size, &len); sysctlnametomib("kstat.zfs.misc.arcstats.hdr_size", MIB_kstat_zfs_misc_arcstats_hdr_size, &len); sysctlnametomib("kstat.zfs.misc.arcstats.other_size", MIB_kstat_zfs_misc_arcstats_other_size, &len); + if (sysctlnametomib("kstat.zfs.misc.arcstats.compressed_size", MIB_kstat_zfs_misc_arcstats_compressed_size, &len) == 0) { + stats->isCompressed = 1; + sysctlnametomib("kstat.zfs.misc.arcstats.uncompressed_size", MIB_kstat_zfs_misc_arcstats_uncompressed_size, &len); + } else { + stats->isCompressed = 0; + } } else { stats->enabled = 0; } @@ -77,5 +85,15 @@ void openzfs_sysctl_updateArcStats(ZfsArcStats *stats) { len = sizeof(stats->other); sysctl(MIB_kstat_zfs_misc_arcstats_other_size, 5, &(stats->other), &len , NULL, 0); stats->other /= 1024; + + if (stats->isCompressed) { + len = sizeof(stats->compressed); + sysctl(MIB_kstat_zfs_misc_arcstats_compressed_size, 5, &(stats->compressed), &len , NULL, 0); + stats->compressed /= 1024; + + len = sizeof(stats->uncompressed); + sysctl(MIB_kstat_zfs_misc_arcstats_uncompressed_size, 5, &(stats->uncompressed), &len , NULL, 0); + stats->uncompressed /= 1024; + } } } From a267003f2f38df5d52ae3f07658c1bbd20b5fb5e Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Tue, 3 Sep 2019 19:56:38 +0000 Subject: [PATCH 9/9] Linux fixes --- linux/LinuxProcessList.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 4596c3bc..1d5700e5 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -988,10 +988,10 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) { switch (buffer[0]) { case 'c': tryRead("c_max", &lpl->zfs.max); - tryReadFlag("compressed", &lpl->zfs.compressed, &lpl->zfs.isCompressed); + tryReadFlag("compressed_size", &lpl->zfs.compressed, lpl->zfs.isCompressed); break; case 'u': - tryRead("uncompressed", &lpl->zfs.uncompressed); + tryRead("uncompressed_size", &lpl->zfs.uncompressed); break; case 's': tryRead("size", &lpl->zfs.size);