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 9fef324a5..26019b689 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 ca9a10dd8..b9017aa48 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 933fe068e..2275349a0 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 7d19600f6..ad23d19b2 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 26019b689..94cbaa198 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 af343fb0b..cf96a7025 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 5dd6ca41a..d8d2ed06c 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 1735e7e3b..3dc7ebf21 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 000000000..e12c46e2c --- /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 000000000..b89be2233 --- /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 ad23d19b2..b850815aa 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 5f38540c6..4d19185cd 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 f30b487d6..749231e17 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 ab90ca74b..4e73c61e4 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 b0456e5b5..e775181e6 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 e12c46e2c..ebd809920 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 b850815aa..b6d2117bf 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 098844809..267e8e947 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 c216a8040..6686d05c7 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 1dce8b67a..52d60a9b7 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 1231217b1..4acda2c40 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 | 14 ++---- 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, 216 insertions(+), 224 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 b6d2117bf..5eee6315a 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 267e8e947..122e0188a 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 6686d05c7..73fbd34fe 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 52d60a9b7..8fbb9c933 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 4acda2c40..f83607754 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 94cbaa198..1cbfdaab8 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 cf96a7025..7c1b7ad40 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 d8d2ed06c..05c0e9224 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 4d19185cd..3e8891046 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 749231e17..353fe6039 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 4e73c61e4..e2a3c6d3f 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 000000000..c33076a4b --- /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 000000000..3697af23d --- /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 000000000..ce48f233e --- /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 000000000..7c04bd793 --- /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 5eee6315a..204a8b7db 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 a29fcb479..8084d1fd9 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 f961b913b..62757ff74 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 2c681852b..b6bc6f5dc 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 a5f2fbc25..26bf44917 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 122e0188a..9b4ba119d 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 8fbb9c933..f9f09b5a4 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 1cbfdaab8..fd6941985 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 05c0e9224..b08a508ec 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 e2a3c6d3f..69f668804 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 8084d1fd9..74ae14ec6 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 ebd809920..9f7028bc9 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 b89be2233..c52083df2 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 ce48f233e..ceee4d109 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 7c04bd793..6e44ac3b1 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 b9017aa48..cb36b6c09 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 2275349a0..d9eba556b 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 204a8b7db..2d159f026 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 f9f09b5a4..286ff16b2 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 f83607754..e17661d61 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 b08a508ec..0986a3dd7 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 3dc7ebf21..0268f2c64 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 3e8891046..4596c3bcd 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 69f668804..f7088cf41 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 e775181e6..5d85eb366 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 74ae14ec6..7dcfe323b 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 62757ff74..3b5aef860 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 b6bc6f5dc..d62ea1d4d 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 c33076a4b..1bfaf47d8 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 3697af23d..ee5d0eddd 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 000000000..ac3944d34 --- /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 000000000..5afcc99e6 --- /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 ceee4d109..c1ab22394 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 4596c3bcd..1d5700e5d 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);