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()