From edd5b80d07544961f8bd184b2d5cc726ea71f5d0 Mon Sep 17 00:00:00 2001 From: cburroughs Date: Tue, 11 Feb 2014 09:15:50 -0500 Subject: [PATCH 1/6] Add arc_summary.py from FreeNAS The arc_summary script is a useful utility for administrators on other ZFS platforms. It provides a quick and easy way to get a high level view of the current ARC state. Historically this was a perl script but it was rewritten in python for FreeNAS. We've decided to adopt the python version instead of the perl version for a few reasons. 1) ZoL has no existing perl dependencies, but it does have a python dependency for scripts such as arcstat.py and dbufstat.py. Using python for arc_summary.py helps us minimize dependencies. 2) Most major Linux distributions already depend heavily on python for their core infrastructure. This means it's very likely to be available even very early in the boot process. Original source: https://github.com/freenas/freenas/blob/master/gui/tools/arc_summary.py Signed-off-by: Brian Behlendorf Signed-off-by: cburroughs Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/Makefile.am | 2 + cmd/arc_summary/arc_summary.py | 1376 ++++++++++++++++++++++++++++++++ 2 files changed, 1378 insertions(+) create mode 100644 cmd/arc_summary/Makefile.am create mode 100755 cmd/arc_summary/arc_summary.py diff --git a/cmd/arc_summary/Makefile.am b/cmd/arc_summary/Makefile.am new file mode 100644 index 000000000..339b71ff3 --- /dev/null +++ b/cmd/arc_summary/Makefile.am @@ -0,0 +1,2 @@ +bin_SCRIPTS = arc_summary.py +EXTRA_DIST = $(bin_SCRIPTS) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py new file mode 100755 index 000000000..a81811a51 --- /dev/null +++ b/cmd/arc_summary/arc_summary.py @@ -0,0 +1,1376 @@ +#!/usr/local/bin/python +# +# $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $ +# +# Copyright (c) 2008 Ben Rockwood , +# Copyright (c) 2010 Martin Matuska , +# Copyright (c) 2010-2011 Jason J. Hellenthal , +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# If you are having troubles when using this script from cron(8) please try +# adjusting your PATH before reporting problems. +# +# /usr/bin & /sbin +# +# Binaries used are: +# +# dc(1), kldstat(8), sed(1), sysctl(8) & vmstat(8) +# +# Binaries that I am working on phasing out are: +# +# dc(1) & sed(1) + +import sys +import time +import getopt +import re + +from subprocess import Popen, PIPE +from decimal import Decimal as D + + +usetunable = True +show_sysctl_descriptions = False +alternate_sysctl_layout = False +kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M) + + +def get_Kstat(): + Kstats = [ + "hw.pagesize", + "hw.physmem", + "kern.maxusers", + "vm.kmem_map_free", + "vm.kmem_map_size", + "vm.kmem_size", + "vm.kmem_size_max", + "vm.kmem_size_min", + "vm.kmem_size_scale", + "vm.stats", + "vm.swap_total", + "vm.swap_reserved", + "kstat.zfs", + "vfs.zfs" + ] + + sysctls = " ".join(str(x) for x in Kstats) + p = Popen("/sbin/sysctl -q %s" % sysctls, stdin=PIPE, + stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) + p.wait() + + kstat_pull = p.communicate()[0].split('\n') + if p.returncode != 0: + sys.exit(1) + + Kstat = {} + for kstat in kstat_pull: + kstat = kstat.strip() + mobj = kstat_pobj.match(kstat) + if mobj: + key = mobj.group(1).strip() + val = mobj.group(2).strip() + Kstat[key] = D(val) + + return Kstat + + +def div1(): + sys.stdout.write("\n") + for i in xrange(18): + sys.stdout.write("%s" % "----") + sys.stdout.write("\n") + + +def div2(): + div1() + sys.stdout.write("\n") + + +def fBytes(Bytes=0, Decimal=2): + kbytes = (2 ** 10) + mbytes = (2 ** 20) + gbytes = (2 ** 30) + tbytes = (2 ** 40) + pbytes = (2 ** 50) + ebytes = (2 ** 60) + zbytes = (2 ** 70) + ybytes = (2 ** 80) + + if Bytes >= ybytes: + return str("%0." + str(Decimal) + "f") % (Bytes / ybytes) + "\tYiB" + elif Bytes >= zbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / zbytes) + "\tZiB" + elif Bytes >= ebytes: + return str("%0." + str(Decimal) + "f") % (Bytes / ebytes) + "\tEiB" + elif Bytes >= pbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / pbytes) + "\tPiB" + elif Bytes >= tbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / tbytes) + "\tTiB" + elif Bytes >= gbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / gbytes) + "\tGiB" + elif Bytes >= mbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / mbytes) + "\tMiB" + elif Bytes >= kbytes: + return str("%0." + str(Decimal) + "f") % (Bytes / kbytes) + "\tKiB" + elif Bytes == 0: + return str("%d" % 0) + "\tBytes" + else: + return str("%d" % Bytes) + "\tBytes" + + +def fHits(Hits=0, Decimal=2): + khits = (10 ** 3) + mhits = (10 ** 6) + bhits = (10 ** 9) + thits = (10 ** 12) + qhits = (10 ** 15) + Qhits = (10 ** 18) + shits = (10 ** 21) + Shits = (10 ** 24) + + if Hits >= Shits: + return str("%0." + str(Decimal) + "f") % (Hits / Shits) + "S" + elif Hits >= shits: + return str("%0." + str(Decimal) + "f") % (Hits / shits) + "s" + elif Hits >= Qhits: + return str("%0." + str(Decimal) + "f") % (Hits / Qhits) + "Q" + elif Hits >= qhits: + return str("%0." + str(Decimal) + "f") % (Hits / qhits) + "q" + elif Hits >= thits: + return str("%0." + str(Decimal) + "f") % (Hits / thits) + "t" + elif Hits >= bhits: + return str("%0." + str(Decimal) + "f") % (Hits / bhits) + "b" + elif Hits >= mhits: + return str("%0." + str(Decimal) + "f") % (Hits / mhits) + "m" + elif Hits >= khits: + return str("%0." + str(Decimal) + "f") % (Hits / khits) + "k" + elif Hits == 0: + return str("%d" % 0) + else: + return str("%d" % Hits) + + +def fPerc(lVal=0, rVal=0, Decimal=2): + if rVal > 0: + return str("%0." + str(Decimal) + "f") % (100 * (lVal / rVal)) + "%" + else: + return str("%0." + str(Decimal) + "f") % 100 + "%" + + +def get_system_memory(Kstat): + def mem_rounded(mem_size): + chip_size = 1 + chip_guess = (int(mem_size) / 8) - 1 + while chip_guess != 0: + chip_guess >>= 1 + chip_size <<= 1 + + mem_round = (int(mem_size / chip_size) + 1) * chip_size + return mem_round + + output = {} + + pagesize = Kstat["hw.pagesize"] + mem_hw = mem_rounded(Kstat["hw.physmem"]) + mem_phys = Kstat["hw.physmem"] + mem_all = Kstat["vm.stats.vm.v_page_count"] * pagesize + mem_wire = Kstat["vm.stats.vm.v_wire_count"] * pagesize + mem_active = Kstat["vm.stats.vm.v_active_count"] * pagesize + mem_inactive = Kstat["vm.stats.vm.v_inactive_count"] * pagesize + mem_cache = Kstat["vm.stats.vm.v_cache_count"] * pagesize + mem_free = Kstat["vm.stats.vm.v_free_count"] * pagesize + + mem_gap_vm = mem_all - ( + mem_wire + mem_active + mem_inactive + mem_cache + mem_free + ) + + mem_total = mem_hw + mem_avail = mem_inactive + mem_cache + mem_free + mem_used = mem_total - mem_avail + output["active"] = { + 'per': fPerc(mem_active, mem_all), + 'num': fBytes(mem_active), + } + output["inact"] = { + 'per': fPerc(mem_inactive, mem_all), + 'num': fBytes(mem_inactive), + } + output["wired"] = { + 'per': fPerc(mem_wire, mem_all), + 'num': fBytes(mem_wire), + } + output["cache"] = { + 'per': fPerc(mem_cache, mem_all), + 'num': fBytes(mem_cache), + } + output["free"] = { + 'per': fPerc(mem_free, mem_all), + 'num': fBytes(mem_free), + } + output["gap"] = { + 'per': fPerc(mem_gap_vm, mem_all), + 'num': fBytes(mem_gap_vm), + } + output["real_installed"] = fBytes(mem_hw) + output["real_available"] = { + 'per': fPerc(mem_phys, mem_hw), + 'num': fBytes(mem_phys), + } + output["real_managed"] = { + 'per': fPerc(mem_all, mem_phys), + 'num': fBytes(mem_all), + } + output["logical_total"] = fBytes(mem_total) + output["logical_used"] = { + 'per': fPerc(mem_used, mem_total), + 'num': fBytes(mem_used), + } + output["logical_free"] = { + 'per': fPerc(mem_avail, mem_total), + 'num': fBytes(mem_avail), + } + + swap_total = Kstat["vm.swap_total"] + output["swap_total"] = fBytes(swap_total) + output["swap_reserved"] = fBytes(Kstat["vm.swap_reserved"]) + + if int(swap_total) > 0: + proc = Popen( + "/usr/sbin/swapinfo -k|tail -1|awk '{print $3}'", + shell=True, + stdout=PIPE, + stderr=PIPE, + ) + try: + swap_used = int(proc.communicate()[0]) + except: + swap_used = 0 + output['swap_used'] = fBytes(swap_used * 1024) + else: + output['swap_used'] = fBytes(0) + + output['kmem_map_size'] = Kstat["vm.kmem_map_size"] + output['kmem_map_free'] = Kstat["vm.kmem_map_free"] + + return output + + +def _system_memory(Kstat): + + arc = get_system_memory(Kstat) + + sys.stdout.write("System Memory:\n") + sys.stdout.write("\n") + sys.stdout.write("\t%s\t%s Active,\t" % ( + arc['active']['per'], + arc['active']['num'], + ) + ) + + sys.stdout.write("%s\t%s Inact\n" % ( + arc['inact']['per'], + arc['inact']['num'], + ) + ) + sys.stdout.write("\t%s\t%s Wired,\t" % ( + arc['wired']['per'], + arc['wired']['num'], + ) + ) + sys.stdout.write("%s\t%s Cache\n" % ( + arc['cache']['per'], + arc['cache']['num'], + ) + ) + sys.stdout.write("\t%s\t%s Free,\t" % ( + arc['free']['per'], + arc['free']['num'], + ) + ) + sys.stdout.write("%s\t%s Gap\n" % ( + arc['gap']['per'], + arc['gap']['num'], + ) + ) + sys.stdout.write("\n") + sys.stdout.write("\tReal Installed:\t\t\t\t%s\n" % arc['real_installed']) + sys.stdout.write("\tReal Available:\t\t\t%s\t%s\n" % ( + arc['real_available']['per'], + arc['real_available']['num'], + ) + ) + sys.stdout.write("\tReal Managed:\t\t\t%s\t%s\n" % ( + arc['real_managed']['per'], + arc['real_managed']['num'], + ) + ) + + sys.stdout.write("\n") + sys.stdout.write("\tLogical Total:\t\t\t\t%s\n" % arc['logical_total']) + sys.stdout.write("\tLogical Used:\t\t\t%s\t%s\n" % ( + arc['logical_used']['per'], + arc['logical_used']['num'], + ) + ) + sys.stdout.write("\tLogical Free:\t\t\t%s\t%s\n" % ( + arc['logical_free']['per'], + arc['logical_free']['num'], + ) + ) + sys.stdout.write("\n") + + cmd1 = """ + /sbin/kldstat | \ + /usr/bin/awk ' + BEGIN { + print "16i 0"; + } + NR > 1 { + print toupper($4) "+"; + } + END { + print "p"; + } + ' | /usr/bin/dc + """ + + cmd2 = """ + /usr/bin/vmstat -m | \ + /usr/bin/sed -Ee '1s/.*/0/;s/.* ([0-9]+)K.*/\\1+/;$s/$/1024*p/' | \ + /usr/bin/dc + """ + + p1 = Popen(cmd1, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) + p2 = Popen(cmd2, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) + + ktext = D(p1.communicate()[0].strip()) + kdata = D(p2.communicate()[0].strip()) + + if p1.returncode != 0 or p2.returncode != 0: + sys.exit(1) + + kmem = ktext + kdata + kmem_map_size = arc['kmem_map_size'] + kmem_map_free = arc['kmem_map_free'] + kmem_map_total = kmem_map_size + kmem_map_free + + sys.stdout.write("Kernel Memory:\t\t\t\t\t%s\n" % fBytes(kmem)) + sys.stdout.write("\tData:\t\t\t\t%s\t%s\n" % (fPerc(kdata, kmem), fBytes(kdata))) + sys.stdout.write("\tText:\t\t\t\t%s\t%s\n\n" % (fPerc(ktext, kmem), fBytes(ktext))) + + sys.stdout.write("Kernel Memory Map:\t\t\t\t%s\n" % fBytes(kmem_map_total)) + sys.stdout.write("\tSize:\t\t\t\t%s\t%s\n" % (fPerc(kmem_map_size, kmem_map_total), fBytes(kmem_map_size))) + sys.stdout.write("\tFree:\t\t\t\t%s\t%s\n" % (fPerc(kmem_map_free, kmem_map_total), fBytes(kmem_map_free))) + + +def get_arc_summary(Kstat): + + output = {} + if "vfs.zfs.version.spa" not in Kstat: + return {} + + spa = Kstat["vfs.zfs.version.spa"] + zpl = Kstat["vfs.zfs.version.zpl"] + memory_throttle_count = Kstat[ + "kstat.zfs.misc.arcstats.memory_throttle_count" + ] + + if memory_throttle_count > 0: + output['health'] = 'THROTTLED' + else: + output['health'] = 'HEALTHY' + + output['storage_pool_ver'] = spa + output['filesystem_ver'] = zpl + output['memory_throttle_count'] = fHits(memory_throttle_count) + + ### ARC Misc. ### + deleted = Kstat["kstat.zfs.misc.arcstats.deleted"] + #evict_skip = Kstat["kstat.zfs.misc.arcstats.evict_skip"] + mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"] + recycle_miss = Kstat["kstat.zfs.misc.arcstats.recycle_miss"] + + ### ARC Misc. ### + output["arc_misc"] = {} + output["arc_misc"]["deleted"] = fHits(deleted) + output["arc_misc"]['recycle_miss'] = fHits(recycle_miss) + output["arc_misc"]['mutex_miss'] = fHits(mutex_miss) + output["arc_misc"]['evict_skips'] = fHits(mutex_miss) + + ### ARC Sizing ### + arc_size = Kstat["kstat.zfs.misc.arcstats.size"] + mru_size = Kstat["kstat.zfs.misc.arcstats.p"] + target_max_size = Kstat["kstat.zfs.misc.arcstats.c_max"] + target_min_size = Kstat["kstat.zfs.misc.arcstats.c_min"] + target_size = Kstat["kstat.zfs.misc.arcstats.c"] + + target_size_ratio = (target_max_size / target_min_size) + + ### ARC Sizing ### + output['arc_sizing'] = {} + output['arc_sizing']['arc_size'] = { + 'per': fPerc(arc_size, target_max_size), + 'num': fBytes(arc_size), + } + output['arc_sizing']['target_max_size'] = { + 'ratio': target_size_ratio, + 'num': fBytes(target_max_size), + } + output['arc_sizing']['target_min_size'] = { + 'per': fPerc(target_min_size, target_max_size), + 'num': fBytes(target_min_size), + } + output['arc_sizing']['target_size'] = { + 'per': fPerc(target_size, target_max_size), + 'num': fBytes(target_size), + } + + ### ARC Hash Breakdown ### + output['arc_hash_break'] = {} + output['arc_hash_break']['hash_chain_max'] = Kstat[ + "kstat.zfs.misc.arcstats.hash_chain_max" + ] + output['arc_hash_break']['hash_chains'] = Kstat[ + "kstat.zfs.misc.arcstats.hash_chains" + ] + output['arc_hash_break']['hash_collisions'] = Kstat[ + "kstat.zfs.misc.arcstats.hash_collisions" + ] + output['arc_hash_break']['hash_elements'] = Kstat[ + "kstat.zfs.misc.arcstats.hash_elements" + ] + output['arc_hash_break']['hash_elements_max'] = Kstat[ + "kstat.zfs.misc.arcstats.hash_elements_max" + ] + + output['arc_size_break'] = {} + if arc_size > target_size: + mfu_size = (arc_size - mru_size) + output['arc_size_break']['recently_used_cache_size'] = { + 'per': fPerc(mru_size, arc_size), + 'num': fBytes(mru_size), + } + output['arc_size_break']['frequently_used_cache_size'] = { + 'per': fPerc(mfu_size, arc_size), + 'num': fBytes(mfu_size), + } + + elif arc_size < target_size: + mfu_size = (target_size - mru_size) + output['arc_size_break']['recently_used_cache_size'] = { + 'per': fPerc(mru_size, target_size), + 'num': fBytes(mru_size), + } + output['arc_size_break']['frequently_used_cache_size'] = { + 'per': fPerc(mfu_size, target_size), + 'num': fBytes(mfu_size), + } + + ### ARC Hash Breakdown ### + hash_chain_max = Kstat["kstat.zfs.misc.arcstats.hash_chain_max"] + hash_chains = Kstat["kstat.zfs.misc.arcstats.hash_chains"] + hash_collisions = Kstat["kstat.zfs.misc.arcstats.hash_collisions"] + hash_elements = Kstat["kstat.zfs.misc.arcstats.hash_elements"] + hash_elements_max = Kstat["kstat.zfs.misc.arcstats.hash_elements_max"] + + output['arc_hash_break'] = {} + output['arc_hash_break']['elements_max'] = fHits(hash_elements_max) + output['arc_hash_break']['elements_current'] = { + 'per': fPerc(hash_elements, hash_elements_max), + 'num': fHits(hash_elements), + } + output['arc_hash_break']['collisions'] = fHits(hash_collisions) + output['arc_hash_break']['chain_max'] = fHits(hash_chain_max) + output['arc_hash_break']['chains'] = fHits(hash_chains) + + return output + + +def _arc_summary(Kstat): + ### ARC Sizing ### + arc = get_arc_summary(Kstat) + + sys.stdout.write("ARC Summary: (%s)\n" % arc['health']) + + sys.stdout.write("\tStorage pool Version:\t\t\t%d\n" % arc['storage_pool_ver']) + sys.stdout.write("\tFilesystem Version:\t\t\t%d\n" % arc['filesystem_ver']) + sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % arc['memory_throttle_count']) + sys.stdout.write("\n") + + ### ARC Misc. ### + sys.stdout.write("ARC Misc:\n") + sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted']) + sys.stdout.write("\tRecycle Misses:\t\t\t\t%s\n" % arc['arc_misc']['recycle_miss']) + sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" % arc['arc_misc']['mutex_miss']) + sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" % arc['arc_misc']['mutex_miss']) + sys.stdout.write("\n") + + ### ARC Sizing ### + sys.stdout.write("ARC Size:\t\t\t\t%s\t%s\n" % ( + arc['arc_sizing']['arc_size']['per'], + arc['arc_sizing']['arc_size']['num'] + ) + ) + sys.stdout.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % ( + arc['arc_sizing']['target_size']['per'], + arc['arc_sizing']['target_size']['num'], + ) + ) + + sys.stdout.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % ( + arc['arc_sizing']['target_min_size']['per'], + arc['arc_sizing']['target_min_size']['num'], + ) + ) + + sys.stdout.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % ( + arc['arc_sizing']['target_max_size']['ratio'], + arc['arc_sizing']['target_max_size']['num'], + ) + ) + + sys.stdout.write("\nARC Size Breakdown:\n") + sys.stdout.write("\tRecently Used Cache Size:\t%s\t%s\n" % ( + arc['arc_size_break']['recently_used_cache_size']['per'], + arc['arc_size_break']['recently_used_cache_size']['num'], + ) + ) + sys.stdout.write("\tFrequently Used Cache Size:\t%s\t%s\n" % ( + arc['arc_size_break']['frequently_used_cache_size']['per'], + arc['arc_size_break']['frequently_used_cache_size']['num'], + ) + ) + + sys.stdout.write("\n") + + ### ARC Hash Breakdown ### + sys.stdout.write("ARC Hash Breakdown:\n") + sys.stdout.write("\tElements Max:\t\t\t\t%s\n" % arc['arc_hash_break']['elements_max']) + sys.stdout.write("\tElements Current:\t\t%s\t%s\n" % ( + arc['arc_hash_break']['elements_current']['per'], + arc['arc_hash_break']['elements_current']['num'], + ) + ) + sys.stdout.write("\tCollisions:\t\t\t\t%s\n" % arc['arc_hash_break']['collisions']) + sys.stdout.write("\tChain Max:\t\t\t\t%s\n" % arc['arc_hash_break']['chain_max']) + sys.stdout.write("\tChains:\t\t\t\t\t%s\n" % arc['arc_hash_break']['chains']) + + +def get_arc_efficiency(Kstat): + output = {} + + if "vfs.zfs.version.spa" not in Kstat: + return + + arc_hits = Kstat["kstat.zfs.misc.arcstats.hits"] + arc_misses = Kstat["kstat.zfs.misc.arcstats.misses"] + demand_data_hits = Kstat["kstat.zfs.misc.arcstats.demand_data_hits"] + demand_data_misses = Kstat["kstat.zfs.misc.arcstats.demand_data_misses"] + demand_metadata_hits = Kstat[ + "kstat.zfs.misc.arcstats.demand_metadata_hits" + ] + demand_metadata_misses = Kstat[ + "kstat.zfs.misc.arcstats.demand_metadata_misses" + ] + mfu_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mfu_ghost_hits"] + mfu_hits = Kstat["kstat.zfs.misc.arcstats.mfu_hits"] + mru_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mru_ghost_hits"] + mru_hits = Kstat["kstat.zfs.misc.arcstats.mru_hits"] + prefetch_data_hits = Kstat["kstat.zfs.misc.arcstats.prefetch_data_hits"] + prefetch_data_misses = Kstat[ + "kstat.zfs.misc.arcstats.prefetch_data_misses" + ] + prefetch_metadata_hits = Kstat[ + "kstat.zfs.misc.arcstats.prefetch_metadata_hits" + ] + prefetch_metadata_misses = Kstat[ + "kstat.zfs.misc.arcstats.prefetch_metadata_misses" + ] + + anon_hits = arc_hits - ( + mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits + ) + arc_accesses_total = (arc_hits + arc_misses) + demand_data_total = (demand_data_hits + demand_data_misses) + prefetch_data_total = (prefetch_data_hits + prefetch_data_misses) + real_hits = (mfu_hits + mru_hits) + + output["total_accesses"] = fHits(arc_accesses_total) + output["cache_hit_ratio"] = { + 'per': fPerc(arc_hits, arc_accesses_total), + 'num': fHits(arc_hits), + } + output["cache_miss_ratio"] = { + 'per': fPerc(arc_misses, arc_accesses_total), + 'num': fHits(arc_misses), + } + output["actual_hit_ratio"] = { + 'per': fPerc(real_hits, arc_accesses_total), + 'num': fHits(real_hits), + } + output["data_demand_efficiency"] = { + 'per': fPerc(demand_data_hits, demand_data_total), + 'num': fHits(demand_data_total), + } + + if prefetch_data_total > 0: + output["data_prefetch_efficiency"] = { + 'per': fPerc(prefetch_data_hits, prefetch_data_total), + 'num': fHits(prefetch_data_total), + } + + if anon_hits > 0: + output["cache_hits_by_cache_list"] = {} + output["cache_hits_by_cache_list"]["anonymously_used"] = { + 'per': fPerc(anon_hits, arc_hits), + 'num': fHits(anon_hits), + } + + output["most_recently_used"] = { + 'per': fPerc(mru_hits, arc_hits), + 'num': fHits(mru_hits), + } + output["most_frequently_used"] = { + 'per': fPerc(mfu_hits, arc_hits), + 'num': fHits(mfu_hits), + } + output["most_recently_used_ghost"] = { + 'per': fPerc(mru_ghost_hits, arc_hits), + 'num': fHits(mru_ghost_hits), + } + output["most_frequently_used_ghost"] = { + 'per': fPerc(mfu_ghost_hits, arc_hits), + 'num': fHits(mfu_ghost_hits), + } + + output["cache_hits_by_data_type"] = {} + output["cache_hits_by_data_type"]["demand_data"] = { + 'per': fPerc(demand_data_hits, arc_hits), + 'num': fHits(demand_data_hits), + } + output["cache_hits_by_data_type"]["prefetch_data"] = { + 'per': fPerc(prefetch_data_hits, arc_hits), + 'num': fHits(prefetch_data_hits), + } + output["cache_hits_by_data_type"]["demand_metadata"] = { + 'per': fPerc(demand_metadata_hits, arc_hits), + 'num': fHits(demand_metadata_hits), + } + output["cache_hits_by_data_type"]["prefetch_metadata"] = { + 'per': fPerc(prefetch_metadata_hits, arc_hits), + 'num': fHits(prefetch_metadata_hits), + } + + output["cache_misses_by_data_type"] = {} + output["cache_misses_by_data_type"]["demand_data"] = { + 'per': fPerc(demand_data_misses, arc_misses), + 'num': fHits(demand_data_misses), + } + output["cache_misses_by_data_type"]["prefetch_data"] = { + 'per': fPerc(prefetch_data_misses, arc_misses), + 'num': fHits(prefetch_data_misses), + } + output["cache_misses_by_data_type"]["demand_metadata"] = { + 'per': fPerc(demand_metadata_misses, arc_misses), + 'num': fHits(demand_metadata_misses), + } + output["cache_misses_by_data_type"]["prefetch_metadata"] = { + 'per': fPerc(prefetch_metadata_misses, arc_misses), + 'num': fHits(prefetch_metadata_misses), + } + + return output + + +def _arc_efficiency(Kstat): + arc = get_arc_efficiency(Kstat) + + sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" % arc['total_accesses']) + sys.stdout.write("\tCache Hit Ratio:\t\t%s\t%s\n" % ( + arc['cache_hit_ratio']['per'], + arc['cache_hit_ratio']['num'], + ) + ) + sys.stdout.write("\tCache Miss Ratio:\t\t%s\t%s\n" % ( + arc['cache_miss_ratio']['per'], + arc['cache_miss_ratio']['num'], + ) + ) + + sys.stdout.write("\tActual Hit Ratio:\t\t%s\t%s\n" % ( + arc['actual_hit_ratio']['per'], + arc['actual_hit_ratio']['num'], + ) + ) + + sys.stdout.write("\n") + sys.stdout.write("\tData Demand Efficiency:\t\t%s\t%s\n" % ( + arc['data_demand_efficiency']['per'], + arc['data_demand_efficiency']['num'], + ) + ) + + if 'data_prefetch_efficiency' in arc: + sys.stdout.write("\tData Prefetch Efficiency:\t%s\t%s\n" % ( + arc['data_prefetch_efficiency']['per'], + arc['data_prefetch_efficiency']['num'], + ) + ) + sys.stdout.write("\n") + + sys.stdout.write("\tCACHE HITS BY CACHE LIST:\n") + if 'cache_hits_by_cache_list' in arc: + sys.stdout.write("\t Anonymously Used:\t\t%s\t%s\n" % ( + arc['cache_hits_by_cache_list']['anonymously_used']['per'], + arc['cache_hits_by_cache_list']['anonymously_used']['num'], + ) + ) + sys.stdout.write("\t Most Recently Used:\t\t%s\t%s\n" % ( + arc['most_recently_used']['per'], + arc['most_recently_used']['num'], + ) + ) + sys.stdout.write("\t Most Frequently Used:\t\t%s\t%s\n" % ( + arc['most_frequently_used']['per'], + arc['most_frequently_used']['num'], + ) + ) + sys.stdout.write("\t Most Recently Used Ghost:\t%s\t%s\n" % ( + arc['most_recently_used_ghost']['per'], + arc['most_recently_used_ghost']['num'], + ) + ) + sys.stdout.write("\t Most Frequently Used Ghost:\t%s\t%s\n" % ( + arc['most_frequently_used_ghost']['per'], + arc['most_frequently_used_ghost']['num'], + ) + ) + + sys.stdout.write("\n\tCACHE HITS BY DATA TYPE:\n") + sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % ( + arc["cache_hits_by_data_type"]['demand_data']['per'], + arc["cache_hits_by_data_type"]['demand_data']['num'], + ) + ) + sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % ( + arc["cache_hits_by_data_type"]['prefetch_data']['per'], + arc["cache_hits_by_data_type"]['prefetch_data']['num'], + ) + ) + sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % ( + arc["cache_hits_by_data_type"]['demand_metadata']['per'], + arc["cache_hits_by_data_type"]['demand_metadata']['num'], + ) + ) + sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % ( + arc["cache_hits_by_data_type"]['prefetch_metadata']['per'], + arc["cache_hits_by_data_type"]['prefetch_metadata']['num'], + ) + ) + + sys.stdout.write("\n\tCACHE MISSES BY DATA TYPE:\n") + sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % ( + arc["cache_misses_by_data_type"]['demand_data']['per'], + arc["cache_misses_by_data_type"]['demand_data']['num'], + ) + ) + sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % ( + arc["cache_misses_by_data_type"]['prefetch_data']['per'], + arc["cache_misses_by_data_type"]['prefetch_data']['num'], + ) + ) + sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % ( + arc["cache_misses_by_data_type"]['demand_metadata']['per'], + arc["cache_misses_by_data_type"]['demand_metadata']['num'], + ) + ) + sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % ( + arc["cache_misses_by_data_type"]['prefetch_metadata']['per'], + arc["cache_misses_by_data_type"]['prefetch_metadata']['num'], + ) + ) + + +def get_l2arc_summary(Kstat): + output = {} + + if "vfs.zfs.version.spa" not in Kstat: + return + + l2_abort_lowmem = Kstat["kstat.zfs.misc.arcstats.l2_abort_lowmem"] + l2_cksum_bad = Kstat["kstat.zfs.misc.arcstats.l2_cksum_bad"] + l2_evict_lock_retry = Kstat["kstat.zfs.misc.arcstats.l2_evict_lock_retry"] + l2_evict_reading = Kstat["kstat.zfs.misc.arcstats.l2_evict_reading"] + l2_feeds = Kstat["kstat.zfs.misc.arcstats.l2_feeds"] + l2_free_on_write = Kstat["kstat.zfs.misc.arcstats.l2_free_on_write"] + l2_hdr_size = Kstat["kstat.zfs.misc.arcstats.l2_hdr_size"] + l2_hits = Kstat["kstat.zfs.misc.arcstats.l2_hits"] + l2_io_error = Kstat["kstat.zfs.misc.arcstats.l2_io_error"] + l2_misses = Kstat["kstat.zfs.misc.arcstats.l2_misses"] + l2_rw_clash = Kstat["kstat.zfs.misc.arcstats.l2_rw_clash"] + l2_size = Kstat["kstat.zfs.misc.arcstats.l2_size"] + l2_write_buffer_bytes_scanned = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_bytes_scanned"] + l2_write_buffer_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_iter"] + l2_write_buffer_list_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_list_iter"] + l2_write_buffer_list_null_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_list_null_iter"] + #l2_write_bytes = Kstat["kstat.zfs.misc.arcstats.l2_write_bytes"] + l2_write_full = Kstat["kstat.zfs.misc.arcstats.l2_write_full"] + #l2_write_in_l2 = Kstat["kstat.zfs.misc.arcstats.l2_write_in_l2"] + l2_write_io_in_progress = Kstat["kstat.zfs.misc.arcstats.l2_write_io_in_progress"] + #l2_write_not_cacheable = Kstat["kstat.zfs.misc.arcstats.l2_write_not_cacheable"] + l2_write_passed_headroom = Kstat["kstat.zfs.misc.arcstats.l2_write_passed_headroom"] + #l2_write_pios = Kstat["kstat.zfs.misc.arcstats.l2_write_pios"] + l2_write_spa_mismatch = Kstat["kstat.zfs.misc.arcstats.l2_write_spa_mismatch"] + l2_write_trylock_fail = Kstat["kstat.zfs.misc.arcstats.l2_write_trylock_fail"] + l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"] + l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"] + #l2_writes_hdr_miss = Kstat["kstat.zfs.misc.arcstats.l2_writes_hdr_miss"] + l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"] + + l2_access_total = (l2_hits + l2_misses) + output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error) + + output['l2_access_total'] = l2_access_total + output['l2_size'] = l2_size + + if l2_size > 0 and l2_access_total > 0: + + if output['l2_health_count'] > 0: + output["health"] = "DEGRADED" + else: + output["health"] = "HEALTHY" + + output["passed_headroom"] = fHits(l2_write_passed_headroom) + output["tried_lock_failure"] = fHits(l2_write_trylock_fail) + output["io_in_progress"] = fHits(l2_write_io_in_progress) + output["low_memory_aborts"] = fHits(l2_abort_lowmem) + output["free_on_write"] = fHits(l2_free_on_write) + output["writes_while_full"] = fHits(l2_write_full) + output["rw_clashes"] = fHits(l2_rw_clash) + output["bad_checksums"] = fHits(l2_cksum_bad) + output["io_errors"] = fHits(l2_io_error) + output["spa_mismatch"] = fHits(l2_write_spa_mismatch) + + output["l2_arc_size"] = {} + output["l2_arc_size"]["adative"] = fBytes(l2_size) + output["l2_arc_size"]["head_size"] = { + 'per': fPerc(l2_hdr_size, l2_size), + 'num': fBytes(l2_hdr_size), + } + + output["l2_arc_evicts"] = {} + output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry) + output["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading) + + output['l2_arc_breakdown'] = {} + output['l2_arc_breakdown']['value'] = fHits(l2_access_total) + output['l2_arc_breakdown']['hit_ratio'] = { + 'per': fPerc(l2_hits, l2_access_total), + 'num': fHits(l2_hits), + } + output['l2_arc_breakdown']['miss_ratio'] = { + 'per': fPerc(l2_misses, l2_access_total), + 'num': fHits(l2_misses), + } + output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds) + + output['l2_arc_buffer'] = {} + output['l2_arc_buffer']['bytes_scanned'] = fBytes(l2_write_buffer_bytes_scanned) + output['l2_arc_buffer']['buffer_iterations'] = fHits(l2_write_buffer_iter) + output['l2_arc_buffer']['list_iterations'] = fHits(l2_write_buffer_list_iter) + output['l2_arc_buffer']['null_list_iterations'] = fHits(l2_write_buffer_list_null_iter) + + output['l2_arc_writes'] = {} + output['l2_writes_done'] = l2_writes_done + output['l2_writes_sent'] = l2_writes_sent + if l2_writes_done != l2_writes_sent: + output['l2_arc_writes']['writes_sent'] = { + 'value': "FAULTED", + 'num': fHits(l2_writes_sent), + } + output['l2_arc_writes']['done_ratio'] = { + 'per': fPerc(l2_writes_done, l2_writes_sent), + 'num': fHits(l2_writes_done), + } + output['l2_arc_writes']['error_ratio'] = { + 'per': fPerc(l2_writes_error, l2_writes_sent), + 'num': fHits(l2_writes_error), + } + else: + output['l2_arc_writes']['writes_sent'] = { + 'per': fPerc(100), + 'num': fHits(l2_writes_sent), + } + + return output + + +def _l2arc_summary(Kstat): + + if not Kstat["vfs.zfs.version.spa"]: + return + + arc = get_l2arc_summary(Kstat) + + if arc['l2_size'] > 0 and arc['l2_access_total'] > 0: + sys.stdout.write("L2 ARC Summary: ") + if arc['l2_health_count'] > 0: + sys.stdout.write("(DEGRADED)\n") + else: + sys.stdout.write("(HEALTHY)\n") + sys.stdout.write("\tPassed Headroom:\t\t\t%s\n" % arc['passed_headroom']) + sys.stdout.write("\tTried Lock Failures:\t\t\t%s\n" % arc['tried_lock_failure']) + sys.stdout.write("\tIO In Progress:\t\t\t\t%s\n" % arc['io_in_progress']) + sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" % arc['low_memory_aborts']) + sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write']) + sys.stdout.write("\tWrites While Full:\t\t\t%s\n" % arc['writes_while_full']) + sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes']) + sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums']) + sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors']) + sys.stdout.write("\tSPA Mismatch:\t\t\t\t%s\n" % arc['spa_mismatch']) + sys.stdout.write("\n") + + sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" % arc["l2_arc_size"]["adative"]) + sys.stdout.write("\tHeader Size:\t\t\t%s\t%s\n" % ( + arc["l2_arc_size"]["head_size"]["per"], + arc["l2_arc_size"]["head_size"]["num"], + ) + ) + sys.stdout.write("\n") + + if arc["l2_arc_evicts"]['lock_retries'] + arc["l2_arc_evicts"]["reading"] > 0: + sys.stdout.write("L2 ARC Evicts:\n") + sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" % arc["l2_arc_evicts"]['lock_retries']) + sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" % arc["l2_arc_evicts"]["reading"]) + sys.stdout.write("\n") + + sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" % arc['l2_arc_breakdown']['value']) + sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( + arc['l2_arc_breakdown']['hit_ratio']['per'], + arc['l2_arc_breakdown']['hit_ratio']['num'], + ) + ) + + sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( + arc['l2_arc_breakdown']['miss_ratio']['per'], + arc['l2_arc_breakdown']['miss_ratio']['num'], + ) + ) + + sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % arc['l2_arc_breakdown']['feeds']) + sys.stdout.write("\n") + + sys.stdout.write("L2 ARC Buffer:\n") + sys.stdout.write("\tBytes Scanned:\t\t\t\t%s\n" % arc['l2_arc_buffer']['bytes_scanned']) + sys.stdout.write("\tBuffer Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['buffer_iterations']) + sys.stdout.write("\tList Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['list_iterations']) + sys.stdout.write("\tNULL List Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['null_list_iterations']) + sys.stdout.write("\n") + + sys.stdout.write("L2 ARC Writes:\n") + if arc['l2_writes_done'] != arc['l2_writes_sent']: + sys.stdout.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % ( + arc['l2_arc_writes']['writes_sent']['value'], + arc['l2_arc_writes']['writes_sent']['num'], + ) + ) + sys.stdout.write("\t Done Ratio:\t\t\t%s\t%s\n" % ( + arc['l2_arc_writes']['done_ratio']['per'], + arc['l2_arc_writes']['done_ratio']['num'], + ) + ) + sys.stdout.write("\t Error Ratio:\t\t\t%s\t%s\n" % ( + arc['l2_arc_writes']['error_ratio']['per'], + arc['l2_arc_writes']['error_ratio']['num'], + ) + ) + else: + sys.stdout.write("\tWrites Sent:\t\t\t%s\t%s\n" % ( + arc['l2_arc_writes']['writes_sent']['per'], + arc['l2_arc_writes']['writes_sent']['num'], + ) + ) + + +def get_dmu_summary(Kstat): + output = {} + + if "vfs.zfs.version.spa" not in Kstat: + return output + + zfetch_bogus_streams = Kstat["kstat.zfs.misc.zfetchstats.bogus_streams"] + zfetch_colinear_hits = Kstat["kstat.zfs.misc.zfetchstats.colinear_hits"] + zfetch_colinear_misses = Kstat["kstat.zfs.misc.zfetchstats.colinear_misses"] + zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"] + zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"] + zfetch_reclaim_failures = Kstat["kstat.zfs.misc.zfetchstats.reclaim_failures"] + zfetch_reclaim_successes = Kstat["kstat.zfs.misc.zfetchstats.reclaim_successes"] + zfetch_streams_noresets = Kstat["kstat.zfs.misc.zfetchstats.streams_noresets"] + zfetch_streams_resets = Kstat["kstat.zfs.misc.zfetchstats.streams_resets"] + zfetch_stride_hits = Kstat["kstat.zfs.misc.zfetchstats.stride_hits"] + zfetch_stride_misses = Kstat["kstat.zfs.misc.zfetchstats.stride_misses"] + + zfetch_access_total = (zfetch_hits + zfetch_misses) + zfetch_colinear_total = (zfetch_colinear_hits + zfetch_colinear_misses) + zfetch_health_count = (zfetch_bogus_streams) + zfetch_reclaim_total = (zfetch_reclaim_successes + zfetch_reclaim_failures) + zfetch_streams_total = (zfetch_streams_resets + zfetch_streams_noresets + zfetch_bogus_streams) + zfetch_stride_total = (zfetch_stride_hits + zfetch_stride_misses) + output['zfetch_access_total'] = zfetch_access_total + + if zfetch_access_total > 0: + + output['file_level_prefetch'] = {} + if zfetch_health_count > 0: + output['file_level_prefetch']['health'] = 'DEGRADED' + else: + output['file_level_prefetch']['health'] = 'HEALTHY' + + output['dmu'] = {} + output['dmu']['efficiency'] = {} + output['dmu']['efficiency']['value'] = fHits(zfetch_access_total) + output['dmu']['efficiency']['hit_ratio'] = { + 'per': fPerc(zfetch_hits, zfetch_access_total), + 'num': fHits(zfetch_hits), + } + output['dmu']['efficiency']['miss_ratio'] = { + 'per': fPerc(zfetch_misses, zfetch_access_total), + 'num': fHits(zfetch_misses), + } + + output['dmu']['colinear'] = {} + output['dmu']['colinear']['value'] = fHits(zfetch_colinear_total) + output['dmu']['colinear']['hit_ratio'] = { + 'per': fPerc(zfetch_colinear_hits, zfetch_colinear_total), + 'num': fHits(zfetch_colinear_hits), + } + output['dmu']['colinear']['miss_ratio'] = { + 'per': fPerc(zfetch_colinear_misses, zfetch_colinear_total), + 'num': fHits(zfetch_colinear_misses), + } + + output['dmu']['stride'] = {} + output['dmu']['stride']['value'] = fHits(zfetch_stride_total) + output['dmu']['stride']['hit_ratio'] = { + 'per': fPerc(zfetch_stride_hits, zfetch_stride_total), + 'num': fHits(zfetch_stride_hits), + } + output['dmu']['stride']['miss_ratio'] = { + 'per': fPerc(zfetch_stride_misses, zfetch_stride_total), + 'num': fHits(zfetch_stride_misses), + } + + output['dmu_misc'] = {} + if zfetch_health_count > 0: + output['dmu_misc']['status'] = "FAULTED" + else: + output['dmu_misc']['status'] = "" + + output['dmu_misc']['reclaim'] = {} + output['dmu_misc']['reclaim']['value'] = fHits(zfetch_reclaim_total) + output['dmu_misc']['reclaim']['successes'] = { + 'per': fPerc(zfetch_reclaim_successes, zfetch_reclaim_total), + 'num': fHits(zfetch_reclaim_successes), + } + output['dmu_misc']['reclaim']['failure'] = { + 'per': fPerc(zfetch_reclaim_failures, zfetch_reclaim_total), + 'num': fHits(zfetch_reclaim_failures), + } + + output['dmu_misc']['streams'] = {} + output['dmu_misc']['streams']['value'] = fHits(zfetch_streams_total) + output['dmu_misc']['streams']['plus_resets'] = { + 'per': fPerc(zfetch_streams_resets, zfetch_streams_total), + 'num': fHits(zfetch_streams_resets), + } + output['dmu_misc']['streams']['neg_resets'] = { + 'per': fPerc(zfetch_streams_noresets, zfetch_streams_total), + 'num': fHits(zfetch_streams_noresets), + } + output['dmu_misc']['streams']['bogus'] = fHits(zfetch_bogus_streams) + + return output + + +def _dmu_summary(Kstat): + + arc = get_dmu_summary(Kstat) + + if arc['zfetch_access_total'] > 0: + sys.stdout.write("File-Level Prefetch: (%s)" % arc['file_level_prefetch']['health']) + + sys.stdout.write("DMU Efficiency:\t\t\t\t\t%s\n" % arc['dmu']['efficiency']['value']) + sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['efficiency']['hit_ratio']['per'], + arc['dmu']['efficiency']['hit_ratio']['num'], + ) + ) + sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['efficiency']['miss_ratio']['per'], + arc['dmu']['efficiency']['miss_ratio']['num'], + ) + ) + + sys.stdout.write("\n") + + sys.stdout.write("\tColinear:\t\t\t\t%s\n" % arc['dmu']['colinear']['value']) + sys.stdout.write("\t Hit Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['colinear']['hit_ratio']['per'], + arc['dmu']['colinear']['hit_ratio']['num'], + ) + ) + + sys.stdout.write("\t Miss Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['colinear']['miss_ratio']['per'], + arc['dmu']['colinear']['miss_ratio']['num'], + ) + ) + + sys.stdout.write("\n") + + sys.stdout.write("\tStride:\t\t\t\t\t%s\n" % arc['dmu']['stride']['value']) + sys.stdout.write("\t Hit Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['stride']['hit_ratio']['per'], + arc['dmu']['stride']['hit_ratio']['num'], + ) + ) + + sys.stdout.write("\t Miss Ratio:\t\t\t%s\t%s\n" % ( + arc['dmu']['stride']['miss_ratio']['per'], + arc['dmu']['stride']['miss_ratio']['num'], + ) + ) + + sys.stdout.write("\n") + sys.stdout.write("DMU Misc: %s\n" % arc['dmu_misc']['status']) + + sys.stdout.write("\tReclaim:\t\t\t\t%s\n" % arc['dmu_misc']['reclaim']['value']) + sys.stdout.write("\t Successes:\t\t\t%s\t%s\n" % ( + arc['dmu_misc']['reclaim']['successes']['per'], + arc['dmu_misc']['reclaim']['successes']['num'], + ) + ) + + sys.stdout.write("\t Failures:\t\t\t%s\t%s\n" % ( + arc['dmu_misc']['reclaim']['failure']['per'], + arc['dmu_misc']['reclaim']['failure']['num'], + ) + ) + + sys.stdout.write("\n\tStreams:\t\t\t\t%s\n" % arc['dmu_misc']['streams']['value']) + sys.stdout.write("\t +Resets:\t\t\t%s\t%s\n" % ( + arc['dmu_misc']['streams']['plus_resets']['per'], + arc['dmu_misc']['streams']['plus_resets']['num'], + ) + ) + + sys.stdout.write("\t -Resets:\t\t\t%s\t%s\n" % ( + arc['dmu_misc']['streams']['neg_resets']['per'], + arc['dmu_misc']['streams']['neg_resets']['num'], + ) + ) + + sys.stdout.write("\t Bogus:\t\t\t\t%s\n" % arc['dmu_misc']['streams']['bogus']) + + +def get_vdev_summary(Kstat): + output = {} + + if "vfs.zfs.version.spa" not in Kstat: + return + + vdev_cache_delegations = Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] + vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"] + vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"] + vdev_cache_total = (vdev_cache_misses + vdev_cache_hits + vdev_cache_delegations) + + output['vdev_cache_total'] = vdev_cache_total + + if vdev_cache_total > 0: + output['summary'] = fHits(vdev_cache_total) + output['hit_ratio'] = { + 'per': fPerc(vdev_cache_hits, vdev_cache_total), + 'num': fHits(vdev_cache_hits), + } + output['miss_ratio'] = { + 'per': fPerc(vdev_cache_misses, vdev_cache_total), + 'num': fHits(vdev_cache_misses), + } + output['delegations'] = { + 'per': fPerc(vdev_cache_delegations, vdev_cache_total), + 'num': fHits(vdev_cache_delegations), + } + + return output + + +def _vdev_summary(Kstat): + arc = get_vdev_summary(Kstat) + + if arc['vdev_cache_total'] > 0: + sys.stdout.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc['summary']) + sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( + arc['hit_ratio']['per'], + arc['hit_ratio']['num'], + )) + sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( + arc['miss_ratio']['per'], + arc['miss_ratio']['num'], + )) + sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % ( + arc['delegations']['per'], + arc['delegations']['num'], + )) + + +def get_systl_summary(Kstat): + output = {} + return output + + +def _sysctl_summary(Kstat): + global show_sysctl_descriptions + global alternate_sysctl_layout + + Tunable = [ + "kern.maxusers", + "vm.kmem_size", + "vm.kmem_size_scale", + "vm.kmem_size_min", + "vm.kmem_size_max", + "vfs.zfs" + ] + + if not usetunable: + return + + sysctl_descriptions = {} + if show_sysctl_descriptions: + tunables = " ".join(str(x) for x in Tunable) + p = Popen("/sbin/sysctl -qde %s" % tunables, stdin=PIPE, + stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) + p.wait() + + descriptions = p.communicate()[0].split('\n') + if p.returncode != 0: + sys.exit(1) + + for tunable in descriptions: + if not tunable: + continue + tunable = tunable.strip() + name, description = tunable.split('=')[:2] + name = name.strip() + description = description.strip() + if not description: + description = "Description unavailable" + sysctl_descriptions[name] = description + + tunables = " ".join(str(x) for x in Tunable) + p = Popen("/sbin/sysctl -qe %s" % tunables, stdin=PIPE, + stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) + p.wait() + + zfs_tunables = p.communicate()[0].split('\n') + if p.returncode != 0: + sys.exit(1) + + sys.stdout.write("ZFS Tunable (sysctl):\n") + for tunable in zfs_tunables: + if not tunable: + continue + tunable = tunable.strip() + name, value = tunable.split("=")[0:2] + name = name.strip() + value = D(value.strip()) + format = "\t%s=%d\n" if alternate_sysctl_layout else "\t%-40s%d\n" + if show_sysctl_descriptions: + sys.stdout.write("\t\# %s\n" % sysctl_descriptions[name]) + sys.stdout.write(format % (name, value)) + + +unSub = [ + _system_memory, + _arc_summary, + _arc_efficiency, + _l2arc_summary, + _dmu_summary, + _vdev_summary, + _sysctl_summary +] + + +def _call_all(): + page = 1 + Kstat = get_Kstat() + for unsub in unSub: + unsub(Kstat) + sys.stdout.write("\t\t\t\t\t\t\t\tPage: %2d" % page) + div2() + page += 1 + + +def zfs_header(): + daydate = time.strftime("%a %b %d %H:%M:%S %Y") + + div1() + sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate) + div2() + + +def main(): + global show_sysctl_descriptions + global alternate_sysctl_layout + + opts, args = getopt.getopt( + sys.argv[1:], "adp:" + ) + + args = {} + for opt, arg in opts: + if opt == '-a': + args['a'] = True + if opt == '-d': + args['d'] = True + if opt == '-p': + args['p'] = arg + + if args: + alternate_sysctl_layout = True if 'a' in args else False + show_sysctl_descriptions = True if 'd' in args else False + try: + zfs_header() + unSub[int(args['p']) - 1]() + div2() + + except: + _call_all() + + else: + _call_all() + + +if __name__ == '__main__': + main() From 53dc1139e7de76045b73ff9c72d75b81653b7012 Mon Sep 17 00:00:00 2001 From: cburroughs Date: Tue, 11 Feb 2014 10:14:55 -0500 Subject: [PATCH 2/6] Modified arc_summary.py to run on linux 1) Comment out stat sections whose kstats are not currently available 2) Port most of arc_summary to use spl kstats 3) Enable l2arc stats 5) Include compressed l2size 4) Minor style fixes / cleanup Signed-off-by: Brian Behlendorf Signed-off-by: cburroughs Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/arc_summary.py | 311 +++------------------------------ 1 file changed, 24 insertions(+), 287 deletions(-) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py index a81811a51..25db1a941 100755 --- a/cmd/arc_summary/arc_summary.py +++ b/cmd/arc_summary/arc_summary.py @@ -1,4 +1,4 @@ -#!/usr/local/bin/python +#!/usr/bin/python # # $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $ # @@ -58,6 +58,14 @@ kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M) def get_Kstat(): + def load_proc_kstats(fn, namespace): + kstats = [line.strip() for line in open(fn)] + del kstats[0:2] + for kstat in kstats: + kstat = kstat.strip() + name, unused, value = kstat.split() + Kstat[namespace + name] = D(value) + Kstats = [ "hw.pagesize", "hw.physmem", @@ -74,28 +82,13 @@ def get_Kstat(): "kstat.zfs", "vfs.zfs" ] - - sysctls = " ".join(str(x) for x in Kstats) - p = Popen("/sbin/sysctl -q %s" % sysctls, stdin=PIPE, - stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) - p.wait() - - kstat_pull = p.communicate()[0].split('\n') - if p.returncode != 0: - sys.exit(1) - Kstat = {} - for kstat in kstat_pull: - kstat = kstat.strip() - mobj = kstat_pobj.match(kstat) - if mobj: - key = mobj.group(1).strip() - val = mobj.group(2).strip() - Kstat[key] = D(val) + load_proc_kstats('/proc/spl/kstat/zfs/arcstats', 'kstat.zfs.misc.arcstats.') + load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats', 'kstat.zfs.misc.zfetchstats.') + load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats', 'kstat.zfs.misc.vdev_cache_stats.') return Kstat - def div1(): sys.stdout.write("\n") for i in xrange(18): @@ -179,220 +172,9 @@ def fPerc(lVal=0, rVal=0, Decimal=2): return str("%0." + str(Decimal) + "f") % 100 + "%" -def get_system_memory(Kstat): - def mem_rounded(mem_size): - chip_size = 1 - chip_guess = (int(mem_size) / 8) - 1 - while chip_guess != 0: - chip_guess >>= 1 - chip_size <<= 1 - - mem_round = (int(mem_size / chip_size) + 1) * chip_size - return mem_round - - output = {} - - pagesize = Kstat["hw.pagesize"] - mem_hw = mem_rounded(Kstat["hw.physmem"]) - mem_phys = Kstat["hw.physmem"] - mem_all = Kstat["vm.stats.vm.v_page_count"] * pagesize - mem_wire = Kstat["vm.stats.vm.v_wire_count"] * pagesize - mem_active = Kstat["vm.stats.vm.v_active_count"] * pagesize - mem_inactive = Kstat["vm.stats.vm.v_inactive_count"] * pagesize - mem_cache = Kstat["vm.stats.vm.v_cache_count"] * pagesize - mem_free = Kstat["vm.stats.vm.v_free_count"] * pagesize - - mem_gap_vm = mem_all - ( - mem_wire + mem_active + mem_inactive + mem_cache + mem_free - ) - - mem_total = mem_hw - mem_avail = mem_inactive + mem_cache + mem_free - mem_used = mem_total - mem_avail - output["active"] = { - 'per': fPerc(mem_active, mem_all), - 'num': fBytes(mem_active), - } - output["inact"] = { - 'per': fPerc(mem_inactive, mem_all), - 'num': fBytes(mem_inactive), - } - output["wired"] = { - 'per': fPerc(mem_wire, mem_all), - 'num': fBytes(mem_wire), - } - output["cache"] = { - 'per': fPerc(mem_cache, mem_all), - 'num': fBytes(mem_cache), - } - output["free"] = { - 'per': fPerc(mem_free, mem_all), - 'num': fBytes(mem_free), - } - output["gap"] = { - 'per': fPerc(mem_gap_vm, mem_all), - 'num': fBytes(mem_gap_vm), - } - output["real_installed"] = fBytes(mem_hw) - output["real_available"] = { - 'per': fPerc(mem_phys, mem_hw), - 'num': fBytes(mem_phys), - } - output["real_managed"] = { - 'per': fPerc(mem_all, mem_phys), - 'num': fBytes(mem_all), - } - output["logical_total"] = fBytes(mem_total) - output["logical_used"] = { - 'per': fPerc(mem_used, mem_total), - 'num': fBytes(mem_used), - } - output["logical_free"] = { - 'per': fPerc(mem_avail, mem_total), - 'num': fBytes(mem_avail), - } - - swap_total = Kstat["vm.swap_total"] - output["swap_total"] = fBytes(swap_total) - output["swap_reserved"] = fBytes(Kstat["vm.swap_reserved"]) - - if int(swap_total) > 0: - proc = Popen( - "/usr/sbin/swapinfo -k|tail -1|awk '{print $3}'", - shell=True, - stdout=PIPE, - stderr=PIPE, - ) - try: - swap_used = int(proc.communicate()[0]) - except: - swap_used = 0 - output['swap_used'] = fBytes(swap_used * 1024) - else: - output['swap_used'] = fBytes(0) - - output['kmem_map_size'] = Kstat["vm.kmem_map_size"] - output['kmem_map_free'] = Kstat["vm.kmem_map_free"] - - return output - - -def _system_memory(Kstat): - - arc = get_system_memory(Kstat) - - sys.stdout.write("System Memory:\n") - sys.stdout.write("\n") - sys.stdout.write("\t%s\t%s Active,\t" % ( - arc['active']['per'], - arc['active']['num'], - ) - ) - - sys.stdout.write("%s\t%s Inact\n" % ( - arc['inact']['per'], - arc['inact']['num'], - ) - ) - sys.stdout.write("\t%s\t%s Wired,\t" % ( - arc['wired']['per'], - arc['wired']['num'], - ) - ) - sys.stdout.write("%s\t%s Cache\n" % ( - arc['cache']['per'], - arc['cache']['num'], - ) - ) - sys.stdout.write("\t%s\t%s Free,\t" % ( - arc['free']['per'], - arc['free']['num'], - ) - ) - sys.stdout.write("%s\t%s Gap\n" % ( - arc['gap']['per'], - arc['gap']['num'], - ) - ) - sys.stdout.write("\n") - sys.stdout.write("\tReal Installed:\t\t\t\t%s\n" % arc['real_installed']) - sys.stdout.write("\tReal Available:\t\t\t%s\t%s\n" % ( - arc['real_available']['per'], - arc['real_available']['num'], - ) - ) - sys.stdout.write("\tReal Managed:\t\t\t%s\t%s\n" % ( - arc['real_managed']['per'], - arc['real_managed']['num'], - ) - ) - - sys.stdout.write("\n") - sys.stdout.write("\tLogical Total:\t\t\t\t%s\n" % arc['logical_total']) - sys.stdout.write("\tLogical Used:\t\t\t%s\t%s\n" % ( - arc['logical_used']['per'], - arc['logical_used']['num'], - ) - ) - sys.stdout.write("\tLogical Free:\t\t\t%s\t%s\n" % ( - arc['logical_free']['per'], - arc['logical_free']['num'], - ) - ) - sys.stdout.write("\n") - - cmd1 = """ - /sbin/kldstat | \ - /usr/bin/awk ' - BEGIN { - print "16i 0"; - } - NR > 1 { - print toupper($4) "+"; - } - END { - print "p"; - } - ' | /usr/bin/dc - """ - - cmd2 = """ - /usr/bin/vmstat -m | \ - /usr/bin/sed -Ee '1s/.*/0/;s/.* ([0-9]+)K.*/\\1+/;$s/$/1024*p/' | \ - /usr/bin/dc - """ - - p1 = Popen(cmd1, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) - p2 = Popen(cmd2, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) - - ktext = D(p1.communicate()[0].strip()) - kdata = D(p2.communicate()[0].strip()) - - if p1.returncode != 0 or p2.returncode != 0: - sys.exit(1) - - kmem = ktext + kdata - kmem_map_size = arc['kmem_map_size'] - kmem_map_free = arc['kmem_map_free'] - kmem_map_total = kmem_map_size + kmem_map_free - - sys.stdout.write("Kernel Memory:\t\t\t\t\t%s\n" % fBytes(kmem)) - sys.stdout.write("\tData:\t\t\t\t%s\t%s\n" % (fPerc(kdata, kmem), fBytes(kdata))) - sys.stdout.write("\tText:\t\t\t\t%s\t%s\n\n" % (fPerc(ktext, kmem), fBytes(ktext))) - - sys.stdout.write("Kernel Memory Map:\t\t\t\t%s\n" % fBytes(kmem_map_total)) - sys.stdout.write("\tSize:\t\t\t\t%s\t%s\n" % (fPerc(kmem_map_size, kmem_map_total), fBytes(kmem_map_size))) - sys.stdout.write("\tFree:\t\t\t\t%s\t%s\n" % (fPerc(kmem_map_free, kmem_map_total), fBytes(kmem_map_free))) - - def get_arc_summary(Kstat): output = {} - if "vfs.zfs.version.spa" not in Kstat: - return {} - - spa = Kstat["vfs.zfs.version.spa"] - zpl = Kstat["vfs.zfs.version.zpl"] memory_throttle_count = Kstat[ "kstat.zfs.misc.arcstats.memory_throttle_count" ] @@ -402,13 +184,10 @@ def get_arc_summary(Kstat): else: output['health'] = 'HEALTHY' - output['storage_pool_ver'] = spa - output['filesystem_ver'] = zpl output['memory_throttle_count'] = fHits(memory_throttle_count) ### ARC Misc. ### deleted = Kstat["kstat.zfs.misc.arcstats.deleted"] - #evict_skip = Kstat["kstat.zfs.misc.arcstats.evict_skip"] mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"] recycle_miss = Kstat["kstat.zfs.misc.arcstats.recycle_miss"] @@ -514,8 +293,6 @@ def _arc_summary(Kstat): sys.stdout.write("ARC Summary: (%s)\n" % arc['health']) - sys.stdout.write("\tStorage pool Version:\t\t\t%d\n" % arc['storage_pool_ver']) - sys.stdout.write("\tFilesystem Version:\t\t\t%d\n" % arc['filesystem_ver']) sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % arc['memory_throttle_count']) sys.stdout.write("\n") @@ -581,9 +358,6 @@ def _arc_summary(Kstat): def get_arc_efficiency(Kstat): output = {} - if "vfs.zfs.version.spa" not in Kstat: - return - arc_hits = Kstat["kstat.zfs.misc.arcstats.hits"] arc_misses = Kstat["kstat.zfs.misc.arcstats.misses"] demand_data_hits = Kstat["kstat.zfs.misc.arcstats.demand_data_hits"] @@ -816,9 +590,6 @@ def _arc_efficiency(Kstat): def get_l2arc_summary(Kstat): output = {} - if "vfs.zfs.version.spa" not in Kstat: - return - l2_abort_lowmem = Kstat["kstat.zfs.misc.arcstats.l2_abort_lowmem"] l2_cksum_bad = Kstat["kstat.zfs.misc.arcstats.l2_cksum_bad"] l2_evict_lock_retry = Kstat["kstat.zfs.misc.arcstats.l2_evict_lock_retry"] @@ -831,22 +602,9 @@ def get_l2arc_summary(Kstat): l2_misses = Kstat["kstat.zfs.misc.arcstats.l2_misses"] l2_rw_clash = Kstat["kstat.zfs.misc.arcstats.l2_rw_clash"] l2_size = Kstat["kstat.zfs.misc.arcstats.l2_size"] - l2_write_buffer_bytes_scanned = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_bytes_scanned"] - l2_write_buffer_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_iter"] - l2_write_buffer_list_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_list_iter"] - l2_write_buffer_list_null_iter = Kstat["kstat.zfs.misc.arcstats.l2_write_buffer_list_null_iter"] - #l2_write_bytes = Kstat["kstat.zfs.misc.arcstats.l2_write_bytes"] - l2_write_full = Kstat["kstat.zfs.misc.arcstats.l2_write_full"] - #l2_write_in_l2 = Kstat["kstat.zfs.misc.arcstats.l2_write_in_l2"] - l2_write_io_in_progress = Kstat["kstat.zfs.misc.arcstats.l2_write_io_in_progress"] - #l2_write_not_cacheable = Kstat["kstat.zfs.misc.arcstats.l2_write_not_cacheable"] - l2_write_passed_headroom = Kstat["kstat.zfs.misc.arcstats.l2_write_passed_headroom"] - #l2_write_pios = Kstat["kstat.zfs.misc.arcstats.l2_write_pios"] - l2_write_spa_mismatch = Kstat["kstat.zfs.misc.arcstats.l2_write_spa_mismatch"] - l2_write_trylock_fail = Kstat["kstat.zfs.misc.arcstats.l2_write_trylock_fail"] + l2_asize = Kstat["kstat.zfs.misc.arcstats.l2_asize"] l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"] l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"] - #l2_writes_hdr_miss = Kstat["kstat.zfs.misc.arcstats.l2_writes_hdr_miss"] l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"] l2_access_total = (l2_hits + l2_misses) @@ -854,6 +612,7 @@ def get_l2arc_summary(Kstat): output['l2_access_total'] = l2_access_total output['l2_size'] = l2_size + output['l2_asize'] = l2_asize if l2_size > 0 and l2_access_total > 0: @@ -862,19 +621,18 @@ def get_l2arc_summary(Kstat): else: output["health"] = "HEALTHY" - output["passed_headroom"] = fHits(l2_write_passed_headroom) - output["tried_lock_failure"] = fHits(l2_write_trylock_fail) - output["io_in_progress"] = fHits(l2_write_io_in_progress) output["low_memory_aborts"] = fHits(l2_abort_lowmem) output["free_on_write"] = fHits(l2_free_on_write) - output["writes_while_full"] = fHits(l2_write_full) output["rw_clashes"] = fHits(l2_rw_clash) output["bad_checksums"] = fHits(l2_cksum_bad) output["io_errors"] = fHits(l2_io_error) - output["spa_mismatch"] = fHits(l2_write_spa_mismatch) output["l2_arc_size"] = {} output["l2_arc_size"]["adative"] = fBytes(l2_size) + output["l2_arc_size"]["actual"] = { + 'per': fPerc(l2_asize, l2_size), + 'num': fBytes(l2_asize) + } output["l2_arc_size"]["head_size"] = { 'per': fPerc(l2_hdr_size, l2_size), 'num': fBytes(l2_hdr_size), @@ -897,10 +655,6 @@ def get_l2arc_summary(Kstat): output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds) output['l2_arc_buffer'] = {} - output['l2_arc_buffer']['bytes_scanned'] = fBytes(l2_write_buffer_bytes_scanned) - output['l2_arc_buffer']['buffer_iterations'] = fHits(l2_write_buffer_iter) - output['l2_arc_buffer']['list_iterations'] = fHits(l2_write_buffer_list_iter) - output['l2_arc_buffer']['null_list_iterations'] = fHits(l2_write_buffer_list_null_iter) output['l2_arc_writes'] = {} output['l2_writes_done'] = l2_writes_done @@ -929,9 +683,6 @@ def get_l2arc_summary(Kstat): def _l2arc_summary(Kstat): - if not Kstat["vfs.zfs.version.spa"]: - return - arc = get_l2arc_summary(Kstat) if arc['l2_size'] > 0 and arc['l2_access_total'] > 0: @@ -940,19 +691,19 @@ def _l2arc_summary(Kstat): sys.stdout.write("(DEGRADED)\n") else: sys.stdout.write("(HEALTHY)\n") - sys.stdout.write("\tPassed Headroom:\t\t\t%s\n" % arc['passed_headroom']) - sys.stdout.write("\tTried Lock Failures:\t\t\t%s\n" % arc['tried_lock_failure']) - sys.stdout.write("\tIO In Progress:\t\t\t\t%s\n" % arc['io_in_progress']) sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" % arc['low_memory_aborts']) sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write']) - sys.stdout.write("\tWrites While Full:\t\t\t%s\n" % arc['writes_while_full']) sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes']) sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums']) sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors']) - sys.stdout.write("\tSPA Mismatch:\t\t\t\t%s\n" % arc['spa_mismatch']) sys.stdout.write("\n") sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" % arc["l2_arc_size"]["adative"]) + sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % ( + arc["l2_arc_size"]["actual"]["per"], + arc["l2_arc_size"]["actual"]["num"], + ) + ) sys.stdout.write("\tHeader Size:\t\t\t%s\t%s\n" % ( arc["l2_arc_size"]["head_size"]["per"], arc["l2_arc_size"]["head_size"]["num"], @@ -982,13 +733,6 @@ def _l2arc_summary(Kstat): sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % arc['l2_arc_breakdown']['feeds']) sys.stdout.write("\n") - sys.stdout.write("L2 ARC Buffer:\n") - sys.stdout.write("\tBytes Scanned:\t\t\t\t%s\n" % arc['l2_arc_buffer']['bytes_scanned']) - sys.stdout.write("\tBuffer Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['buffer_iterations']) - sys.stdout.write("\tList Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['list_iterations']) - sys.stdout.write("\tNULL List Iterations:\t\t\t%s\n" % arc['l2_arc_buffer']['null_list_iterations']) - sys.stdout.write("\n") - sys.stdout.write("L2 ARC Writes:\n") if arc['l2_writes_done'] != arc['l2_writes_sent']: sys.stdout.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % ( @@ -1017,9 +761,6 @@ def _l2arc_summary(Kstat): def get_dmu_summary(Kstat): output = {} - if "vfs.zfs.version.spa" not in Kstat: - return output - zfetch_bogus_streams = Kstat["kstat.zfs.misc.zfetchstats.bogus_streams"] zfetch_colinear_hits = Kstat["kstat.zfs.misc.zfetchstats.colinear_hits"] zfetch_colinear_misses = Kstat["kstat.zfs.misc.zfetchstats.colinear_misses"] @@ -1120,6 +861,7 @@ def _dmu_summary(Kstat): if arc['zfetch_access_total'] > 0: sys.stdout.write("File-Level Prefetch: (%s)" % arc['file_level_prefetch']['health']) + sys.stdout.write("\n") sys.stdout.write("DMU Efficiency:\t\t\t\t\t%s\n" % arc['dmu']['efficiency']['value']) sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( @@ -1198,9 +940,6 @@ def _dmu_summary(Kstat): def get_vdev_summary(Kstat): output = {} - if "vfs.zfs.version.spa" not in Kstat: - return - vdev_cache_delegations = Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"] vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"] @@ -1312,13 +1051,11 @@ def _sysctl_summary(Kstat): unSub = [ - _system_memory, _arc_summary, _arc_efficiency, _l2arc_summary, _dmu_summary, _vdev_summary, - _sysctl_summary ] From 3bfc7f1b2052a794ffceb6a33f5b21f613a479dc Mon Sep 17 00:00:00 2001 From: Kyle Blatter Date: Wed, 5 Nov 2014 10:08:45 -0800 Subject: [PATCH 3/6] Refactor arc_summary to simplify -p processing The -p option is used to specify a specific page of output to be displayed. If omitted, all output pages would be displayed. arc_summary, as it stood, had really kludgy processing code for processing the -p option. It relied on a try-except block which was treated as an if statement and in normal operation would fail any time a user didn't specify the -p option on the command line. When the exception was thrown, the script would then display all output pages. This happened whether the -p option was omitted or malformed. Thus, in the principle use case, an exception would be raised in order to run the script as desired. The same except code would be called regardless of the exception, however, and malformed -p arguments would also cause the script to execute. Additionally, this required the function which handles the case where all output pages were to be displayed, _call_all, to be potentially called from several locations within main. This commit refactors the option processing code to simplify it and make it easier to catch runtime errors in the script. This is done by specializing the try-except block to only have an exception when the -p argument is malformed. When the -p option is correctly selected by the user, it calls a function in the unSub array directly, which will only display one page of output. Finally in the context of this refactoring the page breaks have been removed. Pages seem to have been added into the output in the FreeNAS version of the script. This patch removes pages from the output to more closely resemble the freebsd version of the script. Signed-off-by: Brian Behlendorf Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/arc_summary.py | 42 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py index 25db1a941..1456e58f3 100755 --- a/cmd/arc_summary/arc_summary.py +++ b/cmd/arc_summary/arc_summary.py @@ -97,7 +97,6 @@ def div1(): def div2(): - div1() sys.stdout.write("\n") @@ -1049,7 +1048,6 @@ def _sysctl_summary(Kstat): sys.stdout.write("\t\# %s\n" % sysctl_descriptions[name]) sys.stdout.write(format % (name, value)) - unSub = [ _arc_summary, _arc_efficiency, @@ -1058,17 +1056,6 @@ unSub = [ _vdev_summary, ] - -def _call_all(): - page = 1 - Kstat = get_Kstat() - for unsub in unSub: - unsub(Kstat) - sys.stdout.write("\t\t\t\t\t\t\t\tPage: %2d" % page) - div2() - page += 1 - - def zfs_header(): daydate = time.strftime("%a %b %d %H:%M:%S %Y") @@ -1094,20 +1081,27 @@ def main(): if opt == '-p': args['p'] = arg - if args: - alternate_sysctl_layout = True if 'a' in args else False - show_sysctl_descriptions = True if 'd' in args else False + Kstat = get_Kstat() + + alternate_sysctl_layout = 'a' in args + show_sysctl_descriptions = 'd' in args + + pages = [] + + if 'p' in args: try: - zfs_header() - unSub[int(args['p']) - 1]() - div2() - - except: - _call_all() - + pages.append(unSub[int(args['p']) - 1]) + except IndexError , e: + sys.stderr.write('the argument to -p must be between 1 and ' + + str(len(unSub)) + '\n') + sys.exit() else: - _call_all() + pages = unSub + zfs_header() + for page in pages: + page(Kstat) + div2() if __name__ == '__main__': main() From 6427f39fe08a14e30525b060d606c59d257af94a Mon Sep 17 00:00:00 2001 From: Kyle Blatter Date: Thu, 4 Dec 2014 11:31:54 -0800 Subject: [PATCH 4/6] Add a help option with usage information Add a basic help option and usage description which is consistent with arcstat.py and dbufstat.py. This also adds support for long opts. Signed-off-by: Brian Behlendorf Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/arc_summary.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py index 1456e58f3..2d76df82d 100755 --- a/cmd/arc_summary/arc_summary.py +++ b/cmd/arc_summary/arc_summary.py @@ -1064,22 +1064,43 @@ def zfs_header(): div2() +def usage(): + sys.stdout.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n") + sys.stdout.write("\t -h, --help : " + "Print this help message and exit\n") + sys.stdout.write("\t -a, --alternate : " + "Show an alternate sysctl layout\n") + sys.stdout.write("\t -d, --description : " + "Show the sysctl descriptions\n") + sys.stdout.write("\t -p PAGE, --page=PAGE : " + "Select a single output page to display,\n") + sys.stdout.write("\t " + "should be an integer between 1 and " + str(len(unSub)) + "\n\n") + sys.stdout.write("Examples:\n") + sys.stdout.write("\tarc_summary.py -a\n") + sys.stdout.write("\tarc_summary.py -p 4\n") + sys.stdout.write("\tarc_summary.py -ad\n") + sys.stdout.write("\tarc_summary.py --page=2\n") + def main(): global show_sysctl_descriptions global alternate_sysctl_layout opts, args = getopt.getopt( - sys.argv[1:], "adp:" + sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"] ) args = {} for opt, arg in opts: - if opt == '-a': + if opt in ('-a', '--alternate'): args['a'] = True - if opt == '-d': + if opt in ('-d', '--description'): args['d'] = True - if opt == '-p': + if opt in ('-p', '--page'): args['p'] = arg + if opt in ('-h', '--help'): + usage() + sys.exit() Kstat = get_Kstat() From 65dc685a1db00d741bf75d9df98c8e0e25bf2a71 Mon Sep 17 00:00:00 2001 From: Kyle Blatter Date: Tue, 13 Jan 2015 10:28:55 -0800 Subject: [PATCH 5/6] Force all lines to be 80 columns Ensure this script conforms to the projects style guidelines by limiting line length to 80 columns. Signed-off-by: Brian Behlendorf Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/arc_summary.py | 99 ++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py index 2d76df82d..bf84ca446 100755 --- a/cmd/arc_summary/arc_summary.py +++ b/cmd/arc_summary/arc_summary.py @@ -83,9 +83,12 @@ def get_Kstat(): "vfs.zfs" ] Kstat = {} - load_proc_kstats('/proc/spl/kstat/zfs/arcstats', 'kstat.zfs.misc.arcstats.') - load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats', 'kstat.zfs.misc.zfetchstats.') - load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats', 'kstat.zfs.misc.vdev_cache_stats.') + load_proc_kstats('/proc/spl/kstat/zfs/arcstats', + 'kstat.zfs.misc.arcstats.') + load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats', + 'kstat.zfs.misc.zfetchstats.') + load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats', + 'kstat.zfs.misc.vdev_cache_stats.') return Kstat @@ -292,15 +295,19 @@ def _arc_summary(Kstat): sys.stdout.write("ARC Summary: (%s)\n" % arc['health']) - sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % arc['memory_throttle_count']) + sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % + arc['memory_throttle_count']) sys.stdout.write("\n") ### ARC Misc. ### sys.stdout.write("ARC Misc:\n") sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted']) - sys.stdout.write("\tRecycle Misses:\t\t\t\t%s\n" % arc['arc_misc']['recycle_miss']) - sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" % arc['arc_misc']['mutex_miss']) - sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" % arc['arc_misc']['mutex_miss']) + sys.stdout.write("\tRecycle Misses:\t\t\t\t%s\n" % + arc['arc_misc']['recycle_miss']) + sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" % + arc['arc_misc']['mutex_miss']) + sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" % + arc['arc_misc']['mutex_miss']) sys.stdout.write("\n") ### ARC Sizing ### @@ -343,15 +350,19 @@ def _arc_summary(Kstat): ### ARC Hash Breakdown ### sys.stdout.write("ARC Hash Breakdown:\n") - sys.stdout.write("\tElements Max:\t\t\t\t%s\n" % arc['arc_hash_break']['elements_max']) + sys.stdout.write("\tElements Max:\t\t\t\t%s\n" % + arc['arc_hash_break']['elements_max']) sys.stdout.write("\tElements Current:\t\t%s\t%s\n" % ( arc['arc_hash_break']['elements_current']['per'], arc['arc_hash_break']['elements_current']['num'], ) ) - sys.stdout.write("\tCollisions:\t\t\t\t%s\n" % arc['arc_hash_break']['collisions']) - sys.stdout.write("\tChain Max:\t\t\t\t%s\n" % arc['arc_hash_break']['chain_max']) - sys.stdout.write("\tChains:\t\t\t\t\t%s\n" % arc['arc_hash_break']['chains']) + sys.stdout.write("\tCollisions:\t\t\t\t%s\n" % + arc['arc_hash_break']['collisions']) + sys.stdout.write("\tChain Max:\t\t\t\t%s\n" % + arc['arc_hash_break']['chain_max']) + sys.stdout.write("\tChains:\t\t\t\t\t%s\n" % + arc['arc_hash_break']['chains']) def get_arc_efficiency(Kstat): @@ -480,7 +491,8 @@ def get_arc_efficiency(Kstat): def _arc_efficiency(Kstat): arc = get_arc_efficiency(Kstat) - sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" % arc['total_accesses']) + sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" % + arc['total_accesses']) sys.stdout.write("\tCache Hit Ratio:\t\t%s\t%s\n" % ( arc['cache_hit_ratio']['per'], arc['cache_hit_ratio']['num'], @@ -690,14 +702,16 @@ def _l2arc_summary(Kstat): sys.stdout.write("(DEGRADED)\n") else: sys.stdout.write("(HEALTHY)\n") - sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" % arc['low_memory_aborts']) + sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" % + arc['low_memory_aborts']) sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write']) sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes']) sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums']) sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors']) sys.stdout.write("\n") - sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" % arc["l2_arc_size"]["adative"]) + sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" % + arc["l2_arc_size"]["adative"]) sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % ( arc["l2_arc_size"]["actual"]["per"], arc["l2_arc_size"]["actual"]["num"], @@ -710,13 +724,17 @@ def _l2arc_summary(Kstat): ) sys.stdout.write("\n") - if arc["l2_arc_evicts"]['lock_retries'] + arc["l2_arc_evicts"]["reading"] > 0: + if arc["l2_arc_evicts"]['lock_retries'] + \ + arc["l2_arc_evicts"]["reading"] > 0: sys.stdout.write("L2 ARC Evicts:\n") - sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" % arc["l2_arc_evicts"]['lock_retries']) - sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" % arc["l2_arc_evicts"]["reading"]) + sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" % + arc["l2_arc_evicts"]['lock_retries']) + sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" % + arc["l2_arc_evicts"]["reading"]) sys.stdout.write("\n") - sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" % arc['l2_arc_breakdown']['value']) + sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" % + arc['l2_arc_breakdown']['value']) sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( arc['l2_arc_breakdown']['hit_ratio']['per'], arc['l2_arc_breakdown']['hit_ratio']['num'], @@ -729,7 +747,8 @@ def _l2arc_summary(Kstat): ) ) - sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % arc['l2_arc_breakdown']['feeds']) + sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % + arc['l2_arc_breakdown']['feeds']) sys.stdout.write("\n") sys.stdout.write("L2 ARC Writes:\n") @@ -762,12 +781,16 @@ def get_dmu_summary(Kstat): zfetch_bogus_streams = Kstat["kstat.zfs.misc.zfetchstats.bogus_streams"] zfetch_colinear_hits = Kstat["kstat.zfs.misc.zfetchstats.colinear_hits"] - zfetch_colinear_misses = Kstat["kstat.zfs.misc.zfetchstats.colinear_misses"] + zfetch_colinear_misses = \ + Kstat["kstat.zfs.misc.zfetchstats.colinear_misses"] zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"] zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"] - zfetch_reclaim_failures = Kstat["kstat.zfs.misc.zfetchstats.reclaim_failures"] - zfetch_reclaim_successes = Kstat["kstat.zfs.misc.zfetchstats.reclaim_successes"] - zfetch_streams_noresets = Kstat["kstat.zfs.misc.zfetchstats.streams_noresets"] + zfetch_reclaim_failures = \ + Kstat["kstat.zfs.misc.zfetchstats.reclaim_failures"] + zfetch_reclaim_successes = \ + Kstat["kstat.zfs.misc.zfetchstats.reclaim_successes"] + zfetch_streams_noresets = \ + Kstat["kstat.zfs.misc.zfetchstats.streams_noresets"] zfetch_streams_resets = Kstat["kstat.zfs.misc.zfetchstats.streams_resets"] zfetch_stride_hits = Kstat["kstat.zfs.misc.zfetchstats.stride_hits"] zfetch_stride_misses = Kstat["kstat.zfs.misc.zfetchstats.stride_misses"] @@ -776,7 +799,8 @@ def get_dmu_summary(Kstat): zfetch_colinear_total = (zfetch_colinear_hits + zfetch_colinear_misses) zfetch_health_count = (zfetch_bogus_streams) zfetch_reclaim_total = (zfetch_reclaim_successes + zfetch_reclaim_failures) - zfetch_streams_total = (zfetch_streams_resets + zfetch_streams_noresets + zfetch_bogus_streams) + zfetch_streams_total = (zfetch_streams_resets + zfetch_streams_noresets + + zfetch_bogus_streams) zfetch_stride_total = (zfetch_stride_hits + zfetch_stride_misses) output['zfetch_access_total'] = zfetch_access_total @@ -859,10 +883,12 @@ def _dmu_summary(Kstat): arc = get_dmu_summary(Kstat) if arc['zfetch_access_total'] > 0: - sys.stdout.write("File-Level Prefetch: (%s)" % arc['file_level_prefetch']['health']) + sys.stdout.write("File-Level Prefetch: (%s)" % + arc['file_level_prefetch']['health']) sys.stdout.write("\n") - sys.stdout.write("DMU Efficiency:\t\t\t\t\t%s\n" % arc['dmu']['efficiency']['value']) + sys.stdout.write("DMU Efficiency:\t\t\t\t\t%s\n" % + arc['dmu']['efficiency']['value']) sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( arc['dmu']['efficiency']['hit_ratio']['per'], arc['dmu']['efficiency']['hit_ratio']['num'], @@ -876,7 +902,8 @@ def _dmu_summary(Kstat): sys.stdout.write("\n") - sys.stdout.write("\tColinear:\t\t\t\t%s\n" % arc['dmu']['colinear']['value']) + sys.stdout.write("\tColinear:\t\t\t\t%s\n" % + arc['dmu']['colinear']['value']) sys.stdout.write("\t Hit Ratio:\t\t\t%s\t%s\n" % ( arc['dmu']['colinear']['hit_ratio']['per'], arc['dmu']['colinear']['hit_ratio']['num'], @@ -891,7 +918,8 @@ def _dmu_summary(Kstat): sys.stdout.write("\n") - sys.stdout.write("\tStride:\t\t\t\t\t%s\n" % arc['dmu']['stride']['value']) + sys.stdout.write("\tStride:\t\t\t\t\t%s\n" % + arc['dmu']['stride']['value']) sys.stdout.write("\t Hit Ratio:\t\t\t%s\t%s\n" % ( arc['dmu']['stride']['hit_ratio']['per'], arc['dmu']['stride']['hit_ratio']['num'], @@ -907,7 +935,8 @@ def _dmu_summary(Kstat): sys.stdout.write("\n") sys.stdout.write("DMU Misc: %s\n" % arc['dmu_misc']['status']) - sys.stdout.write("\tReclaim:\t\t\t\t%s\n" % arc['dmu_misc']['reclaim']['value']) + sys.stdout.write("\tReclaim:\t\t\t\t%s\n" % + arc['dmu_misc']['reclaim']['value']) sys.stdout.write("\t Successes:\t\t\t%s\t%s\n" % ( arc['dmu_misc']['reclaim']['successes']['per'], arc['dmu_misc']['reclaim']['successes']['num'], @@ -920,7 +949,8 @@ def _dmu_summary(Kstat): ) ) - sys.stdout.write("\n\tStreams:\t\t\t\t%s\n" % arc['dmu_misc']['streams']['value']) + sys.stdout.write("\n\tStreams:\t\t\t\t%s\n" % + arc['dmu_misc']['streams']['value']) sys.stdout.write("\t +Resets:\t\t\t%s\t%s\n" % ( arc['dmu_misc']['streams']['plus_resets']['per'], arc['dmu_misc']['streams']['plus_resets']['num'], @@ -933,16 +963,19 @@ def _dmu_summary(Kstat): ) ) - sys.stdout.write("\t Bogus:\t\t\t\t%s\n" % arc['dmu_misc']['streams']['bogus']) + sys.stdout.write("\t Bogus:\t\t\t\t%s\n" % + arc['dmu_misc']['streams']['bogus']) def get_vdev_summary(Kstat): output = {} - vdev_cache_delegations = Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] + vdev_cache_delegations = \ + Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"] vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"] - vdev_cache_total = (vdev_cache_misses + vdev_cache_hits + vdev_cache_delegations) + vdev_cache_total = (vdev_cache_misses + vdev_cache_hits + + vdev_cache_delegations) output['vdev_cache_total'] = vdev_cache_total From a6445855492faf94b393e8b6cf7d00f6c8c895f0 Mon Sep 17 00:00:00 2001 From: Kyle Blatter Date: Mon, 12 Jan 2015 13:31:24 -0800 Subject: [PATCH 6/6] Replace sysctl summary with tunables summary. The original script displayed tunable parameters using sysctl calls. This patch modifies this by displaying tunable parameters found in /sys/modules/zfs/parameters/. modinfo calls are used to capture descriptions. Signed-off-by: Brian Behlendorf Signed-off-by: Kyle Blatter Signed-off-by: Ned Bass --- cmd/arc_summary/arc_summary.py | 117 +++++++++++++++------------------ 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/cmd/arc_summary/arc_summary.py b/cmd/arc_summary/arc_summary.py index bf84ca446..15d844b52 100755 --- a/cmd/arc_summary/arc_summary.py +++ b/cmd/arc_summary/arc_summary.py @@ -46,14 +46,14 @@ import sys import time import getopt import re - +from os import listdir from subprocess import Popen, PIPE from decimal import Decimal as D usetunable = True -show_sysctl_descriptions = False -alternate_sysctl_layout = False +show_tunable_descriptions = False +alternate_tunable_layout = False kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M) @@ -1016,70 +1016,59 @@ def _vdev_summary(Kstat): )) -def get_systl_summary(Kstat): - output = {} - return output +def _tunable_summary(Kstat): + global show_tunable_descriptions + global alternate_tunable_layout + names = listdir("/sys/module/zfs/parameters/") -def _sysctl_summary(Kstat): - global show_sysctl_descriptions - global alternate_sysctl_layout + values = {} + for name in names: + with open("/sys/module/zfs/parameters/" + name) as f: value = f.read() + values[name] = value.strip() - Tunable = [ - "kern.maxusers", - "vm.kmem_size", - "vm.kmem_size_scale", - "vm.kmem_size_min", - "vm.kmem_size_max", - "vfs.zfs" - ] + descriptions = {} - if not usetunable: - return + if show_tunable_descriptions: + try: + command = ["/sbin/modinfo", "zfs", "-0"] + p = Popen(command, stdin=PIPE, stdout=PIPE, + stderr=PIPE, shell=False, close_fds=True) + p.wait() - sysctl_descriptions = {} - if show_sysctl_descriptions: - tunables = " ".join(str(x) for x in Tunable) - p = Popen("/sbin/sysctl -qde %s" % tunables, stdin=PIPE, - stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) - p.wait() + description_list = p.communicate()[0].strip().split('\0') - descriptions = p.communicate()[0].split('\n') - if p.returncode != 0: - sys.exit(1) + if p.returncode == 0: + for tunable in description_list: + if tunable[0:5] == 'parm:': + tunable = tunable[5:].strip() + name, description = tunable.split(':', 1) + if not description: + description = "Description unavailable" + descriptions[name] = description + else: + sys.stderr.write("%s: '%s' exited with code %i\n" % + (sys.argv[0], command[0], p.returncode)) + sys.stderr.write("Tunable descriptions will be disabled.\n") + except OSError as e: + sys.stderr.write("%s: Cannot run '%s': %s\n" % + (sys.argv[0], command[0], e.strerror)) + sys.stderr.write("Tunable descriptions will be disabled.\n") - for tunable in descriptions: - if not tunable: - continue - tunable = tunable.strip() - name, description = tunable.split('=')[:2] - name = name.strip() - description = description.strip() - if not description: - description = "Description unavailable" - sysctl_descriptions[name] = description - - tunables = " ".join(str(x) for x in Tunable) - p = Popen("/sbin/sysctl -qe %s" % tunables, stdin=PIPE, - stdout=PIPE, stderr=PIPE, shell=True, close_fds=True) - p.wait() - - zfs_tunables = p.communicate()[0].split('\n') - if p.returncode != 0: - sys.exit(1) - - sys.stdout.write("ZFS Tunable (sysctl):\n") - for tunable in zfs_tunables: - if not tunable: + sys.stdout.write("ZFS Tunable:\n") + for name in names: + if not name: continue - tunable = tunable.strip() - name, value = tunable.split("=")[0:2] - name = name.strip() - value = D(value.strip()) - format = "\t%s=%d\n" if alternate_sysctl_layout else "\t%-40s%d\n" - if show_sysctl_descriptions: - sys.stdout.write("\t\# %s\n" % sysctl_descriptions[name]) - sys.stdout.write(format % (name, value)) + + format = "\t%-50s%s\n" + if alternate_tunable_layout: + format = "\t%s=%s\n" + + if show_tunable_descriptions and descriptions.has_key(name): + sys.stdout.write("\t# %s\n" % descriptions[name]) + + sys.stdout.write(format % (name, values[name])) + unSub = [ _arc_summary, @@ -1087,8 +1076,10 @@ unSub = [ _l2arc_summary, _dmu_summary, _vdev_summary, + _tunable_summary ] + def zfs_header(): daydate = time.strftime("%a %b %d %H:%M:%S %Y") @@ -1116,8 +1107,8 @@ def usage(): sys.stdout.write("\tarc_summary.py --page=2\n") def main(): - global show_sysctl_descriptions - global alternate_sysctl_layout + global show_tunable_descriptions + global alternate_tunable_layout opts, args = getopt.getopt( sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"] @@ -1137,8 +1128,8 @@ def main(): Kstat = get_Kstat() - alternate_sysctl_layout = 'a' in args - show_sysctl_descriptions = 'd' in args + alternate_tunable_layout = 'a' in args + show_tunable_descriptions = 'd' in args pages = []