1716fd348SMartin Matuska#!/usr/bin/env python3 2716fd348SMartin Matuska# 3716fd348SMartin Matuska# Copyright (c) 2008 Ben Rockwood <benr@cuddletech.com>, 4716fd348SMartin Matuska# Copyright (c) 2010 Martin Matuska <mm@FreeBSD.org>, 5716fd348SMartin Matuska# Copyright (c) 2010-2011 Jason J. Hellenthal <jhell@DataIX.net>, 6716fd348SMartin Matuska# Copyright (c) 2017 Scot W. Stevenson <scot.stevenson@gmail.com> 7716fd348SMartin Matuska# All rights reserved. 8716fd348SMartin Matuska# 9716fd348SMartin Matuska# Redistribution and use in source and binary forms, with or without 10716fd348SMartin Matuska# modification, are permitted provided that the following conditions 11716fd348SMartin Matuska# are met: 12716fd348SMartin Matuska# 13716fd348SMartin Matuska# 1. Redistributions of source code must retain the above copyright 14716fd348SMartin Matuska# notice, this list of conditions and the following disclaimer. 15716fd348SMartin Matuska# 2. Redistributions in binary form must reproduce the above copyright 16716fd348SMartin Matuska# notice, this list of conditions and the following disclaimer in the 17716fd348SMartin Matuska# documentation and/or other materials provided with the distribution. 18716fd348SMartin Matuska# 19716fd348SMartin Matuska# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20716fd348SMartin Matuska# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21716fd348SMartin Matuska# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22716fd348SMartin Matuska# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 23716fd348SMartin Matuska# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24716fd348SMartin Matuska# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25716fd348SMartin Matuska# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26716fd348SMartin Matuska# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27716fd348SMartin Matuska# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28716fd348SMartin Matuska# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29716fd348SMartin Matuska# SUCH DAMAGE. 30716fd348SMartin Matuska"""Print statistics on the ZFS ARC Cache and other information 31716fd348SMartin Matuska 32716fd348SMartin MatuskaProvides basic information on the ARC, its efficiency, the L2ARC (if present), 33716fd348SMartin Matuskathe Data Management Unit (DMU), Virtual Devices (VDEVs), and tunables. See 34716fd348SMartin Matuskathe in-source documentation and code at 35716fd348SMartin Matuskahttps://github.com/openzfs/zfs/blob/master/module/zfs/arc.c for details. 36716fd348SMartin MatuskaThe original introduction to arc_summary can be found at 37716fd348SMartin Matuskahttp://cuddletech.com/?p=454 38716fd348SMartin Matuska""" 39716fd348SMartin Matuska 40716fd348SMartin Matuskaimport argparse 41716fd348SMartin Matuskaimport os 42716fd348SMartin Matuskaimport subprocess 43716fd348SMartin Matuskaimport sys 44716fd348SMartin Matuskaimport time 45716fd348SMartin Matuskaimport errno 46716fd348SMartin Matuska 47716fd348SMartin Matuska# We can't use env -S portably, and we need python3 -u to handle pipes in 48716fd348SMartin Matuska# the shell abruptly closing the way we want to, so... 49716fd348SMartin Matuskaimport io 50716fd348SMartin Matuskaif isinstance(sys.__stderr__.buffer, io.BufferedWriter): 51716fd348SMartin Matuska os.execv(sys.executable, [sys.executable, "-u"] + sys.argv) 52716fd348SMartin Matuska 53716fd348SMartin MatuskaDESCRIPTION = 'Print ARC and other statistics for OpenZFS' 54716fd348SMartin MatuskaINDENT = ' '*8 55716fd348SMartin MatuskaLINE_LENGTH = 72 56716fd348SMartin MatuskaDATE_FORMAT = '%a %b %d %H:%M:%S %Y' 57716fd348SMartin MatuskaTITLE = 'ZFS Subsystem Report' 58716fd348SMartin Matuska 59716fd348SMartin MatuskaSECTIONS = 'arc archits dmu l2arc spl tunables vdev zil'.split() 60716fd348SMartin MatuskaSECTION_HELP = 'print info from one section ('+' '.join(SECTIONS)+')' 61716fd348SMartin Matuska 62716fd348SMartin Matuska# Tunables and SPL are handled separately because they come from 63716fd348SMartin Matuska# different sources 64716fd348SMartin MatuskaSECTION_PATHS = {'arc': 'arcstats', 65716fd348SMartin Matuska 'dmu': 'dmu_tx', 66716fd348SMartin Matuska 'l2arc': 'arcstats', # L2ARC stuff lives in arcstats 67716fd348SMartin Matuska 'zfetch': 'zfetchstats', 68716fd348SMartin Matuska 'zil': 'zil'} 69716fd348SMartin Matuska 70716fd348SMartin Matuskaparser = argparse.ArgumentParser(description=DESCRIPTION) 71716fd348SMartin Matuskaparser.add_argument('-a', '--alternate', action='store_true', default=False, 72716fd348SMartin Matuska help='use alternate formatting for tunables and SPL', 73716fd348SMartin Matuska dest='alt') 74716fd348SMartin Matuskaparser.add_argument('-d', '--description', action='store_true', default=False, 75716fd348SMartin Matuska help='print descriptions with tunables and SPL', 76716fd348SMartin Matuska dest='desc') 77716fd348SMartin Matuskaparser.add_argument('-g', '--graph', action='store_true', default=False, 78716fd348SMartin Matuska help='print graph on ARC use and exit', dest='graph') 79716fd348SMartin Matuskaparser.add_argument('-p', '--page', type=int, dest='page', 80716fd348SMartin Matuska help='print page by number (DEPRECATED, use "-s")') 81716fd348SMartin Matuskaparser.add_argument('-r', '--raw', action='store_true', default=False, 82716fd348SMartin Matuska help='dump all available data with minimal formatting', 83716fd348SMartin Matuska dest='raw') 84716fd348SMartin Matuskaparser.add_argument('-s', '--section', dest='section', help=SECTION_HELP) 85716fd348SMartin MatuskaARGS = parser.parse_args() 86716fd348SMartin Matuska 87716fd348SMartin Matuska 88716fd348SMartin Matuskaif sys.platform.startswith('freebsd'): 89716fd348SMartin Matuska # Requires py36-sysctl on FreeBSD 90716fd348SMartin Matuska import sysctl 91716fd348SMartin Matuska 92716fd348SMartin Matuska def is_value(ctl): 93716fd348SMartin Matuska return ctl.type != sysctl.CTLTYPE_NODE 94716fd348SMartin Matuska 95716fd348SMartin Matuska def namefmt(ctl, base='vfs.zfs.'): 96716fd348SMartin Matuska # base is removed from the name 97716fd348SMartin Matuska cut = len(base) 98716fd348SMartin Matuska return ctl.name[cut:] 99716fd348SMartin Matuska 100716fd348SMartin Matuska def load_kstats(section): 101716fd348SMartin Matuska base = 'kstat.zfs.misc.{section}.'.format(section=section) 102716fd348SMartin Matuska fmt = lambda kstat: '{name} : {value}'.format(name=namefmt(kstat, base), 103716fd348SMartin Matuska value=kstat.value) 104716fd348SMartin Matuska kstats = sysctl.filter(base) 105716fd348SMartin Matuska return [fmt(kstat) for kstat in kstats if is_value(kstat)] 106716fd348SMartin Matuska 107716fd348SMartin Matuska def get_params(base): 108716fd348SMartin Matuska ctls = sysctl.filter(base) 109716fd348SMartin Matuska return {namefmt(ctl): str(ctl.value) for ctl in ctls if is_value(ctl)} 110716fd348SMartin Matuska 111716fd348SMartin Matuska def get_tunable_params(): 112716fd348SMartin Matuska return get_params('vfs.zfs') 113716fd348SMartin Matuska 114716fd348SMartin Matuska def get_vdev_params(): 115716fd348SMartin Matuska return get_params('vfs.zfs.vdev') 116716fd348SMartin Matuska 117716fd348SMartin Matuska def get_version_impl(request): 118716fd348SMartin Matuska # FreeBSD reports versions for zpl and spa instead of zfs and spl. 119716fd348SMartin Matuska name = {'zfs': 'zpl', 120716fd348SMartin Matuska 'spl': 'spa'}[request] 121716fd348SMartin Matuska mib = 'vfs.zfs.version.{}'.format(name) 122716fd348SMartin Matuska version = sysctl.filter(mib)[0].value 123716fd348SMartin Matuska return '{} version {}'.format(name, version) 124716fd348SMartin Matuska 125716fd348SMartin Matuska def get_descriptions(_request): 126716fd348SMartin Matuska ctls = sysctl.filter('vfs.zfs') 127716fd348SMartin Matuska return {namefmt(ctl): ctl.description for ctl in ctls if is_value(ctl)} 128716fd348SMartin Matuska 129716fd348SMartin Matuska 130716fd348SMartin Matuskaelif sys.platform.startswith('linux'): 131716fd348SMartin Matuska KSTAT_PATH = '/proc/spl/kstat/zfs' 132716fd348SMartin Matuska SPL_PATH = '/sys/module/spl/parameters' 133716fd348SMartin Matuska TUNABLES_PATH = '/sys/module/zfs/parameters' 134716fd348SMartin Matuska 135716fd348SMartin Matuska def load_kstats(section): 136716fd348SMartin Matuska path = os.path.join(KSTAT_PATH, section) 137716fd348SMartin Matuska with open(path) as f: 138716fd348SMartin Matuska return list(f)[2:] # Get rid of header 139716fd348SMartin Matuska 140716fd348SMartin Matuska def get_params(basepath): 141716fd348SMartin Matuska """Collect information on the Solaris Porting Layer (SPL) or the 142716fd348SMartin Matuska tunables, depending on the PATH given. Does not check if PATH is 143716fd348SMartin Matuska legal. 144716fd348SMartin Matuska """ 145716fd348SMartin Matuska result = {} 146716fd348SMartin Matuska for name in os.listdir(basepath): 147716fd348SMartin Matuska path = os.path.join(basepath, name) 148716fd348SMartin Matuska with open(path) as f: 149716fd348SMartin Matuska value = f.read() 150716fd348SMartin Matuska result[name] = value.strip() 151716fd348SMartin Matuska return result 152716fd348SMartin Matuska 153716fd348SMartin Matuska def get_spl_params(): 154716fd348SMartin Matuska return get_params(SPL_PATH) 155716fd348SMartin Matuska 156716fd348SMartin Matuska def get_tunable_params(): 157716fd348SMartin Matuska return get_params(TUNABLES_PATH) 158716fd348SMartin Matuska 159716fd348SMartin Matuska def get_vdev_params(): 160716fd348SMartin Matuska return get_params(TUNABLES_PATH) 161716fd348SMartin Matuska 162716fd348SMartin Matuska def get_version_impl(request): 163716fd348SMartin Matuska # The original arc_summary called /sbin/modinfo/{spl,zfs} to get 164716fd348SMartin Matuska # the version information. We switch to /sys/module/{spl,zfs}/version 165716fd348SMartin Matuska # to make sure we get what is really loaded in the kernel 166716fd348SMartin Matuska try: 167716fd348SMartin Matuska with open("/sys/module/{}/version".format(request)) as f: 168716fd348SMartin Matuska return f.read().strip() 169716fd348SMartin Matuska except: 170716fd348SMartin Matuska return "(unknown)" 171716fd348SMartin Matuska 172716fd348SMartin Matuska def get_descriptions(request): 173716fd348SMartin Matuska """Get the descriptions of the Solaris Porting Layer (SPL) or the 174716fd348SMartin Matuska tunables, return with minimal formatting. 175716fd348SMartin Matuska """ 176716fd348SMartin Matuska 177716fd348SMartin Matuska if request not in ('spl', 'zfs'): 178716fd348SMartin Matuska print('ERROR: description of "{0}" requested)'.format(request)) 179716fd348SMartin Matuska sys.exit(1) 180716fd348SMartin Matuska 181716fd348SMartin Matuska descs = {} 182716fd348SMartin Matuska target_prefix = 'parm:' 183716fd348SMartin Matuska 184716fd348SMartin Matuska # We would prefer to do this with /sys/modules -- see the discussion at 185716fd348SMartin Matuska # get_version() -- but there isn't a way to get the descriptions from 186716fd348SMartin Matuska # there, so we fall back on modinfo 187716fd348SMartin Matuska command = ["/sbin/modinfo", request, "-0"] 188716fd348SMartin Matuska 189716fd348SMartin Matuska info = '' 190716fd348SMartin Matuska 191716fd348SMartin Matuska try: 192716fd348SMartin Matuska 193716fd348SMartin Matuska info = subprocess.run(command, stdout=subprocess.PIPE, 194716fd348SMartin Matuska check=True, universal_newlines=True) 195716fd348SMartin Matuska raw_output = info.stdout.split('\0') 196716fd348SMartin Matuska 197716fd348SMartin Matuska except subprocess.CalledProcessError: 198716fd348SMartin Matuska print("Error: Descriptions not available", 199716fd348SMartin Matuska "(can't access kernel module)") 200716fd348SMartin Matuska sys.exit(1) 201716fd348SMartin Matuska 202716fd348SMartin Matuska for line in raw_output: 203716fd348SMartin Matuska 204716fd348SMartin Matuska if not line.startswith(target_prefix): 205716fd348SMartin Matuska continue 206716fd348SMartin Matuska 207716fd348SMartin Matuska line = line[len(target_prefix):].strip() 208716fd348SMartin Matuska name, raw_desc = line.split(':', 1) 209716fd348SMartin Matuska desc = raw_desc.rsplit('(', 1)[0] 210716fd348SMartin Matuska 211716fd348SMartin Matuska if desc == '': 212716fd348SMartin Matuska desc = '(No description found)' 213716fd348SMartin Matuska 214716fd348SMartin Matuska descs[name.strip()] = desc.strip() 215716fd348SMartin Matuska 216716fd348SMartin Matuska return descs 217716fd348SMartin Matuska 218716fd348SMartin Matuskadef handle_unraisableException(exc_type, exc_value=None, exc_traceback=None, 219716fd348SMartin Matuska err_msg=None, object=None): 220716fd348SMartin Matuska handle_Exception(exc_type, object, exc_traceback) 221716fd348SMartin Matuska 222716fd348SMartin Matuskadef handle_Exception(ex_cls, ex, tb): 223716fd348SMartin Matuska if ex_cls is KeyboardInterrupt: 224716fd348SMartin Matuska sys.exit() 225716fd348SMartin Matuska 226716fd348SMartin Matuska if ex_cls is BrokenPipeError: 227716fd348SMartin Matuska # It turns out that while sys.exit() triggers an exception 228716fd348SMartin Matuska # not handled message on Python 3.8+, os._exit() does not. 229716fd348SMartin Matuska os._exit(0) 230716fd348SMartin Matuska 231716fd348SMartin Matuska if ex_cls is OSError: 232716fd348SMartin Matuska if ex.errno == errno.ENOTCONN: 233716fd348SMartin Matuska sys.exit() 234716fd348SMartin Matuska 235716fd348SMartin Matuska raise ex 236716fd348SMartin Matuska 237716fd348SMartin Matuskaif hasattr(sys,'unraisablehook'): # Python 3.8+ 238716fd348SMartin Matuska sys.unraisablehook = handle_unraisableException 239716fd348SMartin Matuskasys.excepthook = handle_Exception 240716fd348SMartin Matuska 241716fd348SMartin Matuska 242716fd348SMartin Matuskadef cleanup_line(single_line): 243716fd348SMartin Matuska """Format a raw line of data from /proc and isolate the name value 244716fd348SMartin Matuska part, returning a tuple with each. Currently, this gets rid of the 245716fd348SMartin Matuska middle '4'. For example "arc_no_grow 4 0" returns the tuple 246716fd348SMartin Matuska ("arc_no_grow", "0"). 247716fd348SMartin Matuska """ 248716fd348SMartin Matuska name, _, value = single_line.split() 249716fd348SMartin Matuska 250716fd348SMartin Matuska return name, value 251716fd348SMartin Matuska 252716fd348SMartin Matuska 253716fd348SMartin Matuskadef draw_graph(kstats_dict): 254716fd348SMartin Matuska """Draw a primitive graph representing the basic information on the 255716fd348SMartin Matuska ARC -- its size and the proportion used by MFU and MRU -- and quit. 256716fd348SMartin Matuska We use max size of the ARC to calculate how full it is. This is a 257716fd348SMartin Matuska very rough representation. 258716fd348SMartin Matuska """ 259716fd348SMartin Matuska 260716fd348SMartin Matuska arc_stats = isolate_section('arcstats', kstats_dict) 261716fd348SMartin Matuska 262716fd348SMartin Matuska GRAPH_INDENT = ' '*4 263ce4dcb97SMartin Matuska GRAPH_WIDTH = 70 264ce4dcb97SMartin Matuska arc_max = int(arc_stats['c_max']) 265716fd348SMartin Matuska arc_size = f_bytes(arc_stats['size']) 266ce4dcb97SMartin Matuska arc_perc = f_perc(arc_stats['size'], arc_max) 267ce4dcb97SMartin Matuska data_size = f_bytes(arc_stats['data_size']) 268ce4dcb97SMartin Matuska meta_size = f_bytes(arc_stats['metadata_size']) 269716fd348SMartin Matuska dnode_size = f_bytes(arc_stats['dnode_size']) 270716fd348SMartin Matuska 271ce4dcb97SMartin Matuska info_form = ('ARC: {0} ({1}) Data: {2} Meta: {3} Dnode: {4}') 272ce4dcb97SMartin Matuska info_line = info_form.format(arc_size, arc_perc, data_size, meta_size, 273ce4dcb97SMartin Matuska dnode_size) 274716fd348SMartin Matuska info_spc = ' '*int((GRAPH_WIDTH-len(info_line))/2) 275716fd348SMartin Matuska info_line = GRAPH_INDENT+info_spc+info_line 276716fd348SMartin Matuska 277716fd348SMartin Matuska graph_line = GRAPH_INDENT+'+'+('-'*(GRAPH_WIDTH-2))+'+' 278716fd348SMartin Matuska 279ce4dcb97SMartin Matuska arc_perc = float(int(arc_stats['size'])/arc_max) 280ce4dcb97SMartin Matuska data_perc = float(int(arc_stats['data_size'])/arc_max) 281ce4dcb97SMartin Matuska meta_perc = float(int(arc_stats['metadata_size'])/arc_max) 282ce4dcb97SMartin Matuska dnode_perc = float(int(arc_stats['dnode_size'])/arc_max) 283716fd348SMartin Matuska total_ticks = float(arc_perc)*GRAPH_WIDTH 284ce4dcb97SMartin Matuska data_ticks = data_perc*GRAPH_WIDTH 285ce4dcb97SMartin Matuska meta_ticks = meta_perc*GRAPH_WIDTH 286ce4dcb97SMartin Matuska dnode_ticks = dnode_perc*GRAPH_WIDTH 287ce4dcb97SMartin Matuska other_ticks = total_ticks-(data_ticks+meta_ticks+dnode_ticks) 288716fd348SMartin Matuska 289ce4dcb97SMartin Matuska core_form = 'D'*int(data_ticks)+'M'*int(meta_ticks)+'N'*int(dnode_ticks)+\ 290ce4dcb97SMartin Matuska 'O'*int(other_ticks) 291716fd348SMartin Matuska core_spc = ' '*(GRAPH_WIDTH-(2+len(core_form))) 292716fd348SMartin Matuska core_line = GRAPH_INDENT+'|'+core_form+core_spc+'|' 293716fd348SMartin Matuska 294716fd348SMartin Matuska for line in ('', info_line, graph_line, core_line, graph_line, ''): 295716fd348SMartin Matuska print(line) 296716fd348SMartin Matuska 297716fd348SMartin Matuska 298716fd348SMartin Matuskadef f_bytes(byte_string): 299716fd348SMartin Matuska """Return human-readable representation of a byte value in 300716fd348SMartin Matuska powers of 2 (eg "KiB" for "kibibytes", etc) to two decimal 301716fd348SMartin Matuska points. Values smaller than one KiB are returned without 302716fd348SMartin Matuska decimal points. Note "bytes" is a reserved keyword. 303716fd348SMartin Matuska """ 304716fd348SMartin Matuska 305716fd348SMartin Matuska prefixes = ([2**80, "YiB"], # yobibytes (yotta) 306716fd348SMartin Matuska [2**70, "ZiB"], # zebibytes (zetta) 307716fd348SMartin Matuska [2**60, "EiB"], # exbibytes (exa) 308716fd348SMartin Matuska [2**50, "PiB"], # pebibytes (peta) 309716fd348SMartin Matuska [2**40, "TiB"], # tebibytes (tera) 310716fd348SMartin Matuska [2**30, "GiB"], # gibibytes (giga) 311716fd348SMartin Matuska [2**20, "MiB"], # mebibytes (mega) 312716fd348SMartin Matuska [2**10, "KiB"]) # kibibytes (kilo) 313716fd348SMartin Matuska 314716fd348SMartin Matuska bites = int(byte_string) 315716fd348SMartin Matuska 316716fd348SMartin Matuska if bites >= 2**10: 317716fd348SMartin Matuska for limit, unit in prefixes: 318716fd348SMartin Matuska 319716fd348SMartin Matuska if bites >= limit: 320716fd348SMartin Matuska value = bites / limit 321716fd348SMartin Matuska break 322716fd348SMartin Matuska 323716fd348SMartin Matuska result = '{0:.1f} {1}'.format(value, unit) 324716fd348SMartin Matuska else: 325716fd348SMartin Matuska result = '{0} Bytes'.format(bites) 326716fd348SMartin Matuska 327716fd348SMartin Matuska return result 328716fd348SMartin Matuska 329716fd348SMartin Matuska 330716fd348SMartin Matuskadef f_hits(hits_string): 331716fd348SMartin Matuska """Create a human-readable representation of the number of hits. 332716fd348SMartin Matuska The single-letter symbols used are SI to avoid the confusion caused 333716fd348SMartin Matuska by the different "short scale" and "long scale" representations in 334716fd348SMartin Matuska English, which use the same words for different values. See 335716fd348SMartin Matuska https://en.wikipedia.org/wiki/Names_of_large_numbers and: 336716fd348SMartin Matuska https://physics.nist.gov/cuu/Units/prefixes.html 337716fd348SMartin Matuska """ 338716fd348SMartin Matuska 339716fd348SMartin Matuska numbers = ([10**24, 'Y'], # yotta (septillion) 340716fd348SMartin Matuska [10**21, 'Z'], # zetta (sextillion) 341716fd348SMartin Matuska [10**18, 'E'], # exa (quintrillion) 342716fd348SMartin Matuska [10**15, 'P'], # peta (quadrillion) 343716fd348SMartin Matuska [10**12, 'T'], # tera (trillion) 344716fd348SMartin Matuska [10**9, 'G'], # giga (billion) 345716fd348SMartin Matuska [10**6, 'M'], # mega (million) 346716fd348SMartin Matuska [10**3, 'k']) # kilo (thousand) 347716fd348SMartin Matuska 348716fd348SMartin Matuska hits = int(hits_string) 349716fd348SMartin Matuska 350716fd348SMartin Matuska if hits >= 1000: 351716fd348SMartin Matuska for limit, symbol in numbers: 352716fd348SMartin Matuska 353716fd348SMartin Matuska if hits >= limit: 354716fd348SMartin Matuska value = hits/limit 355716fd348SMartin Matuska break 356716fd348SMartin Matuska 357716fd348SMartin Matuska result = "%0.1f%s" % (value, symbol) 358716fd348SMartin Matuska else: 359716fd348SMartin Matuska result = "%d" % hits 360716fd348SMartin Matuska 361716fd348SMartin Matuska return result 362716fd348SMartin Matuska 363716fd348SMartin Matuska 364716fd348SMartin Matuskadef f_perc(value1, value2): 365716fd348SMartin Matuska """Calculate percentage and return in human-readable form. If 366716fd348SMartin Matuska rounding produces the result '0.0' though the first number is 367716fd348SMartin Matuska not zero, include a 'less-than' symbol to avoid confusion. 368716fd348SMartin Matuska Division by zero is handled by returning 'n/a'; no error 369716fd348SMartin Matuska is called. 370716fd348SMartin Matuska """ 371716fd348SMartin Matuska 372716fd348SMartin Matuska v1 = float(value1) 373716fd348SMartin Matuska v2 = float(value2) 374716fd348SMartin Matuska 375716fd348SMartin Matuska try: 376716fd348SMartin Matuska perc = 100 * v1/v2 377716fd348SMartin Matuska except ZeroDivisionError: 378716fd348SMartin Matuska result = 'n/a' 379716fd348SMartin Matuska else: 380716fd348SMartin Matuska result = '{0:0.1f} %'.format(perc) 381716fd348SMartin Matuska 382716fd348SMartin Matuska if result == '0.0 %' and v1 > 0: 383716fd348SMartin Matuska result = '< 0.1 %' 384716fd348SMartin Matuska 385716fd348SMartin Matuska return result 386716fd348SMartin Matuska 387716fd348SMartin Matuska 388716fd348SMartin Matuskadef format_raw_line(name, value): 389716fd348SMartin Matuska """For the --raw option for the tunable and SPL outputs, decide on the 390716fd348SMartin Matuska correct formatting based on the --alternate flag. 391716fd348SMartin Matuska """ 392716fd348SMartin Matuska 393716fd348SMartin Matuska if ARGS.alt: 394716fd348SMartin Matuska result = '{0}{1}={2}'.format(INDENT, name, value) 395716fd348SMartin Matuska else: 396716fd348SMartin Matuska # Right-align the value within the line length if it fits, 397716fd348SMartin Matuska # otherwise just separate it from the name by a single space. 398716fd348SMartin Matuska fit = LINE_LENGTH - len(INDENT) - len(name) 399716fd348SMartin Matuska overflow = len(value) + 1 400716fd348SMartin Matuska w = max(fit, overflow) 401716fd348SMartin Matuska result = '{0}{1}{2:>{w}}'.format(INDENT, name, value, w=w) 402716fd348SMartin Matuska 403716fd348SMartin Matuska return result 404716fd348SMartin Matuska 405716fd348SMartin Matuska 406716fd348SMartin Matuskadef get_kstats(): 407716fd348SMartin Matuska """Collect information on the ZFS subsystem. The step does not perform any 408716fd348SMartin Matuska further processing, giving us the option to only work on what is actually 409716fd348SMartin Matuska needed. The name "kstat" is a holdover from the Solaris utility of the same 410716fd348SMartin Matuska name. 411716fd348SMartin Matuska """ 412716fd348SMartin Matuska 413716fd348SMartin Matuska result = {} 414716fd348SMartin Matuska 415716fd348SMartin Matuska for section in SECTION_PATHS.values(): 416716fd348SMartin Matuska if section not in result: 417716fd348SMartin Matuska result[section] = load_kstats(section) 418716fd348SMartin Matuska 419716fd348SMartin Matuska return result 420716fd348SMartin Matuska 421716fd348SMartin Matuska 422716fd348SMartin Matuskadef get_version(request): 423716fd348SMartin Matuska """Get the version number of ZFS or SPL on this machine for header. 424716fd348SMartin Matuska Returns an error string, but does not raise an error, if we can't 425716fd348SMartin Matuska get the ZFS/SPL version. 426716fd348SMartin Matuska """ 427716fd348SMartin Matuska 428716fd348SMartin Matuska if request not in ('spl', 'zfs'): 429716fd348SMartin Matuska error_msg = '(ERROR: "{0}" requested)'.format(request) 430716fd348SMartin Matuska return error_msg 431716fd348SMartin Matuska 432716fd348SMartin Matuska return get_version_impl(request) 433716fd348SMartin Matuska 434716fd348SMartin Matuska 435716fd348SMartin Matuskadef print_header(): 436716fd348SMartin Matuska """Print the initial heading with date and time as well as info on the 437716fd348SMartin Matuska kernel and ZFS versions. This is not called for the graph. 438716fd348SMartin Matuska """ 439716fd348SMartin Matuska 440716fd348SMartin Matuska # datetime is now recommended over time but we keep the exact formatting 441716fd348SMartin Matuska # from the older version of arc_summary in case there are scripts 442716fd348SMartin Matuska # that expect it in this way 443716fd348SMartin Matuska daydate = time.strftime(DATE_FORMAT) 444716fd348SMartin Matuska spc_date = LINE_LENGTH-len(daydate) 445716fd348SMartin Matuska sys_version = os.uname() 446716fd348SMartin Matuska 447716fd348SMartin Matuska sys_msg = sys_version.sysname+' '+sys_version.release 448716fd348SMartin Matuska zfs = get_version('zfs') 449716fd348SMartin Matuska spc_zfs = LINE_LENGTH-len(zfs) 450716fd348SMartin Matuska 451716fd348SMartin Matuska machine_msg = 'Machine: '+sys_version.nodename+' ('+sys_version.machine+')' 452716fd348SMartin Matuska spl = get_version('spl') 453716fd348SMartin Matuska spc_spl = LINE_LENGTH-len(spl) 454716fd348SMartin Matuska 455716fd348SMartin Matuska print('\n'+('-'*LINE_LENGTH)) 456716fd348SMartin Matuska print('{0:<{spc}}{1}'.format(TITLE, daydate, spc=spc_date)) 457716fd348SMartin Matuska print('{0:<{spc}}{1}'.format(sys_msg, zfs, spc=spc_zfs)) 458716fd348SMartin Matuska print('{0:<{spc}}{1}\n'.format(machine_msg, spl, spc=spc_spl)) 459716fd348SMartin Matuska 460716fd348SMartin Matuska 461716fd348SMartin Matuskadef print_raw(kstats_dict): 462716fd348SMartin Matuska """Print all available data from the system in a minimally sorted format. 463716fd348SMartin Matuska This can be used as a source to be piped through 'grep'. 464716fd348SMartin Matuska """ 465716fd348SMartin Matuska 466716fd348SMartin Matuska sections = sorted(kstats_dict.keys()) 467716fd348SMartin Matuska 468716fd348SMartin Matuska for section in sections: 469716fd348SMartin Matuska 470716fd348SMartin Matuska print('\n{0}:'.format(section.upper())) 471716fd348SMartin Matuska lines = sorted(kstats_dict[section]) 472716fd348SMartin Matuska 473716fd348SMartin Matuska for line in lines: 474716fd348SMartin Matuska name, value = cleanup_line(line) 475716fd348SMartin Matuska print(format_raw_line(name, value)) 476716fd348SMartin Matuska 477716fd348SMartin Matuska # Tunables and SPL must be handled separately because they come from a 478716fd348SMartin Matuska # different source and have descriptions the user might request 479716fd348SMartin Matuska print() 480716fd348SMartin Matuska section_spl() 481716fd348SMartin Matuska section_tunables() 482716fd348SMartin Matuska 483716fd348SMartin Matuska 484716fd348SMartin Matuskadef isolate_section(section_name, kstats_dict): 485716fd348SMartin Matuska """From the complete information on all sections, retrieve only those 486716fd348SMartin Matuska for one section. 487716fd348SMartin Matuska """ 488716fd348SMartin Matuska 489716fd348SMartin Matuska try: 490716fd348SMartin Matuska section_data = kstats_dict[section_name] 491716fd348SMartin Matuska except KeyError: 492716fd348SMartin Matuska print('ERROR: Data on {0} not available'.format(section_data)) 493716fd348SMartin Matuska sys.exit(1) 494716fd348SMartin Matuska 495716fd348SMartin Matuska section_dict = dict(cleanup_line(l) for l in section_data) 496716fd348SMartin Matuska 497716fd348SMartin Matuska return section_dict 498716fd348SMartin Matuska 499716fd348SMartin Matuska 500716fd348SMartin Matuska# Formatted output helper functions 501716fd348SMartin Matuska 502716fd348SMartin Matuska 503716fd348SMartin Matuskadef prt_1(text, value): 504716fd348SMartin Matuska """Print text and one value, no indent""" 505716fd348SMartin Matuska spc = ' '*(LINE_LENGTH-(len(text)+len(value))) 506716fd348SMartin Matuska print('{0}{spc}{1}'.format(text, value, spc=spc)) 507716fd348SMartin Matuska 508716fd348SMartin Matuska 509716fd348SMartin Matuskadef prt_i1(text, value): 510716fd348SMartin Matuska """Print text and one value, with indent""" 511716fd348SMartin Matuska spc = ' '*(LINE_LENGTH-(len(INDENT)+len(text)+len(value))) 512716fd348SMartin Matuska print(INDENT+'{0}{spc}{1}'.format(text, value, spc=spc)) 513716fd348SMartin Matuska 514716fd348SMartin Matuska 515716fd348SMartin Matuskadef prt_2(text, value1, value2): 516716fd348SMartin Matuska """Print text and two values, no indent""" 517716fd348SMartin Matuska values = '{0:>9} {1:>9}'.format(value1, value2) 518716fd348SMartin Matuska spc = ' '*(LINE_LENGTH-(len(text)+len(values)+2)) 519716fd348SMartin Matuska print('{0}{spc} {1}'.format(text, values, spc=spc)) 520716fd348SMartin Matuska 521716fd348SMartin Matuska 522716fd348SMartin Matuskadef prt_i2(text, value1, value2): 523716fd348SMartin Matuska """Print text and two values, with indent""" 524716fd348SMartin Matuska values = '{0:>9} {1:>9}'.format(value1, value2) 525716fd348SMartin Matuska spc = ' '*(LINE_LENGTH-(len(INDENT)+len(text)+len(values)+2)) 526716fd348SMartin Matuska print(INDENT+'{0}{spc} {1}'.format(text, values, spc=spc)) 527716fd348SMartin Matuska 528716fd348SMartin Matuska 529716fd348SMartin Matuska# The section output concentrates on important parameters instead of 530716fd348SMartin Matuska# being exhaustive (that is what the --raw parameter is for) 531716fd348SMartin Matuska 532716fd348SMartin Matuska 533716fd348SMartin Matuskadef section_arc(kstats_dict): 534716fd348SMartin Matuska """Give basic information on the ARC, MRU and MFU. This is the first 535716fd348SMartin Matuska and most used section. 536716fd348SMartin Matuska """ 537716fd348SMartin Matuska 538716fd348SMartin Matuska arc_stats = isolate_section('arcstats', kstats_dict) 539716fd348SMartin Matuska 540ce4dcb97SMartin Matuska memory_all = arc_stats['memory_all_bytes'] 541ce4dcb97SMartin Matuska memory_free = arc_stats['memory_free_bytes'] 542ce4dcb97SMartin Matuska memory_avail = arc_stats['memory_available_bytes'] 543716fd348SMartin Matuska arc_size = arc_stats['size'] 544716fd348SMartin Matuska arc_target_size = arc_stats['c'] 545716fd348SMartin Matuska arc_max = arc_stats['c_max'] 546716fd348SMartin Matuska arc_min = arc_stats['c_min'] 547ce4dcb97SMartin Matuska dnode_limit = arc_stats['arc_dnode_limit'] 548ce4dcb97SMartin Matuska 549ce4dcb97SMartin Matuska print('ARC status:') 550ce4dcb97SMartin Matuska prt_i1('Total memory size:', f_bytes(memory_all)) 551ce4dcb97SMartin Matuska prt_i2('Min target size:', f_perc(arc_min, memory_all), f_bytes(arc_min)) 552ce4dcb97SMartin Matuska prt_i2('Max target size:', f_perc(arc_max, memory_all), f_bytes(arc_max)) 553ce4dcb97SMartin Matuska prt_i2('Target size (adaptive):', 554ce4dcb97SMartin Matuska f_perc(arc_size, arc_max), f_bytes(arc_target_size)) 555ce4dcb97SMartin Matuska prt_i2('Current size:', f_perc(arc_size, arc_max), f_bytes(arc_size)) 556ce4dcb97SMartin Matuska prt_i1('Free memory size:', f_bytes(memory_free)) 557ce4dcb97SMartin Matuska prt_i1('Available memory size:', f_bytes(memory_avail)) 558ce4dcb97SMartin Matuska print() 559ce4dcb97SMartin Matuska 560ce4dcb97SMartin Matuska compressed_size = arc_stats['compressed_size'] 561ce4dcb97SMartin Matuska overhead_size = arc_stats['overhead_size'] 562ce4dcb97SMartin Matuska bonus_size = arc_stats['bonus_size'] 563ce4dcb97SMartin Matuska dnode_size = arc_stats['dnode_size'] 564ce4dcb97SMartin Matuska dbuf_size = arc_stats['dbuf_size'] 565ce4dcb97SMartin Matuska hdr_size = arc_stats['hdr_size'] 566ce4dcb97SMartin Matuska l2_hdr_size = arc_stats['l2_hdr_size'] 567ce4dcb97SMartin Matuska abd_chunk_waste_size = arc_stats['abd_chunk_waste_size'] 568ce4dcb97SMartin Matuska 5697a7741afSMartin Matuska prt_1('ARC structural breakdown (current size):', f_bytes(arc_size)) 570ce4dcb97SMartin Matuska prt_i2('Compressed size:', 571ce4dcb97SMartin Matuska f_perc(compressed_size, arc_size), f_bytes(compressed_size)) 572ce4dcb97SMartin Matuska prt_i2('Overhead size:', 573ce4dcb97SMartin Matuska f_perc(overhead_size, arc_size), f_bytes(overhead_size)) 574ce4dcb97SMartin Matuska prt_i2('Bonus size:', 575ce4dcb97SMartin Matuska f_perc(bonus_size, arc_size), f_bytes(bonus_size)) 576ce4dcb97SMartin Matuska prt_i2('Dnode size:', 577ce4dcb97SMartin Matuska f_perc(dnode_size, arc_size), f_bytes(dnode_size)) 578ce4dcb97SMartin Matuska prt_i2('Dbuf size:', 579ce4dcb97SMartin Matuska f_perc(dbuf_size, arc_size), f_bytes(dbuf_size)) 580ce4dcb97SMartin Matuska prt_i2('Header size:', 581ce4dcb97SMartin Matuska f_perc(hdr_size, arc_size), f_bytes(hdr_size)) 582ce4dcb97SMartin Matuska prt_i2('L2 header size:', 583ce4dcb97SMartin Matuska f_perc(l2_hdr_size, arc_size), f_bytes(l2_hdr_size)) 584ce4dcb97SMartin Matuska prt_i2('ABD chunk waste size:', 585ce4dcb97SMartin Matuska f_perc(abd_chunk_waste_size, arc_size), f_bytes(abd_chunk_waste_size)) 586ce4dcb97SMartin Matuska print() 587ce4dcb97SMartin Matuska 5882a58b312SMartin Matuska meta = arc_stats['meta'] 5892a58b312SMartin Matuska pd = arc_stats['pd'] 5902a58b312SMartin Matuska pm = arc_stats['pm'] 591ce4dcb97SMartin Matuska data_size = arc_stats['data_size'] 592ce4dcb97SMartin Matuska metadata_size = arc_stats['metadata_size'] 5932a58b312SMartin Matuska anon_data = arc_stats['anon_data'] 5942a58b312SMartin Matuska anon_metadata = arc_stats['anon_metadata'] 5952a58b312SMartin Matuska mfu_data = arc_stats['mfu_data'] 5962a58b312SMartin Matuska mfu_metadata = arc_stats['mfu_metadata'] 597ce4dcb97SMartin Matuska mfu_edata = arc_stats['mfu_evictable_data'] 598ce4dcb97SMartin Matuska mfu_emetadata = arc_stats['mfu_evictable_metadata'] 5992a58b312SMartin Matuska mru_data = arc_stats['mru_data'] 6002a58b312SMartin Matuska mru_metadata = arc_stats['mru_metadata'] 601ce4dcb97SMartin Matuska mru_edata = arc_stats['mru_evictable_data'] 602ce4dcb97SMartin Matuska mru_emetadata = arc_stats['mru_evictable_metadata'] 6032a58b312SMartin Matuska mfug_data = arc_stats['mfu_ghost_data'] 6042a58b312SMartin Matuska mfug_metadata = arc_stats['mfu_ghost_metadata'] 6052a58b312SMartin Matuska mrug_data = arc_stats['mru_ghost_data'] 6062a58b312SMartin Matuska mrug_metadata = arc_stats['mru_ghost_metadata'] 6072a58b312SMartin Matuska unc_data = arc_stats['uncached_data'] 6082a58b312SMartin Matuska unc_metadata = arc_stats['uncached_metadata'] 6092a58b312SMartin Matuska caches_size = int(anon_data)+int(anon_metadata)+\ 6102a58b312SMartin Matuska int(mfu_data)+int(mfu_metadata)+int(mru_data)+int(mru_metadata)+\ 6112a58b312SMartin Matuska int(unc_data)+int(unc_metadata) 612ce4dcb97SMartin Matuska 613ce4dcb97SMartin Matuska prt_1('ARC types breakdown (compressed + overhead):', f_bytes(caches_size)) 614ce4dcb97SMartin Matuska prt_i2('Data size:', 615ce4dcb97SMartin Matuska f_perc(data_size, caches_size), f_bytes(data_size)) 616ce4dcb97SMartin Matuska prt_i2('Metadata size:', 617ce4dcb97SMartin Matuska f_perc(metadata_size, caches_size), f_bytes(metadata_size)) 618ce4dcb97SMartin Matuska print() 619ce4dcb97SMartin Matuska 620ce4dcb97SMartin Matuska prt_1('ARC states breakdown (compressed + overhead):', f_bytes(caches_size)) 6212a58b312SMartin Matuska prt_i2('Anonymous data size:', 6222a58b312SMartin Matuska f_perc(anon_data, caches_size), f_bytes(anon_data)) 6232a58b312SMartin Matuska prt_i2('Anonymous metadata size:', 6242a58b312SMartin Matuska f_perc(anon_metadata, caches_size), f_bytes(anon_metadata)) 6252a58b312SMartin Matuska s = 4294967296 6262a58b312SMartin Matuska v = (s-int(pd))*(s-int(meta))/s 6272a58b312SMartin Matuska prt_i2('MFU data target:', f_perc(v, s), 6282a58b312SMartin Matuska f_bytes(v / 65536 * caches_size / 65536)) 6292a58b312SMartin Matuska prt_i2('MFU data size:', 6302a58b312SMartin Matuska f_perc(mfu_data, caches_size), f_bytes(mfu_data)) 631ce4dcb97SMartin Matuska prt_i2('MFU evictable data size:', 632ce4dcb97SMartin Matuska f_perc(mfu_edata, caches_size), f_bytes(mfu_edata)) 6332a58b312SMartin Matuska prt_i1('MFU ghost data size:', f_bytes(mfug_data)) 6342a58b312SMartin Matuska v = (s-int(pm))*int(meta)/s 6352a58b312SMartin Matuska prt_i2('MFU metadata target:', f_perc(v, s), 6362a58b312SMartin Matuska f_bytes(v / 65536 * caches_size / 65536)) 6372a58b312SMartin Matuska prt_i2('MFU metadata size:', 6382a58b312SMartin Matuska f_perc(mfu_metadata, caches_size), f_bytes(mfu_metadata)) 639ce4dcb97SMartin Matuska prt_i2('MFU evictable metadata size:', 640ce4dcb97SMartin Matuska f_perc(mfu_emetadata, caches_size), f_bytes(mfu_emetadata)) 6412a58b312SMartin Matuska prt_i1('MFU ghost metadata size:', f_bytes(mfug_metadata)) 6422a58b312SMartin Matuska v = int(pd)*(s-int(meta))/s 6432a58b312SMartin Matuska prt_i2('MRU data target:', f_perc(v, s), 6442a58b312SMartin Matuska f_bytes(v / 65536 * caches_size / 65536)) 6452a58b312SMartin Matuska prt_i2('MRU data size:', 6462a58b312SMartin Matuska f_perc(mru_data, caches_size), f_bytes(mru_data)) 647ce4dcb97SMartin Matuska prt_i2('MRU evictable data size:', 648ce4dcb97SMartin Matuska f_perc(mru_edata, caches_size), f_bytes(mru_edata)) 6492a58b312SMartin Matuska prt_i1('MRU ghost data size:', f_bytes(mrug_data)) 6502a58b312SMartin Matuska v = int(pm)*int(meta)/s 6512a58b312SMartin Matuska prt_i2('MRU metadata target:', f_perc(v, s), 6522a58b312SMartin Matuska f_bytes(v / 65536 * caches_size / 65536)) 6532a58b312SMartin Matuska prt_i2('MRU metadata size:', 6542a58b312SMartin Matuska f_perc(mru_metadata, caches_size), f_bytes(mru_metadata)) 655ce4dcb97SMartin Matuska prt_i2('MRU evictable metadata size:', 656ce4dcb97SMartin Matuska f_perc(mru_emetadata, caches_size), f_bytes(mru_emetadata)) 6572a58b312SMartin Matuska prt_i1('MRU ghost metadata size:', f_bytes(mrug_metadata)) 65815f0b8c3SMartin Matuska prt_i2('Uncached data size:', 6592a58b312SMartin Matuska f_perc(unc_data, caches_size), f_bytes(unc_data)) 6602a58b312SMartin Matuska prt_i2('Uncached metadata size:', 6612a58b312SMartin Matuska f_perc(unc_metadata, caches_size), f_bytes(unc_metadata)) 662716fd348SMartin Matuska print() 663716fd348SMartin Matuska 664716fd348SMartin Matuska print('ARC hash breakdown:') 665*718519f4SMartin Matuska prt_i1('Elements:', f_hits(arc_stats['hash_elements'])) 666716fd348SMartin Matuska prt_i1('Collisions:', f_hits(arc_stats['hash_collisions'])) 667716fd348SMartin Matuska 668716fd348SMartin Matuska prt_i1('Chain max:', f_hits(arc_stats['hash_chain_max'])) 669716fd348SMartin Matuska prt_i1('Chains:', f_hits(arc_stats['hash_chains'])) 670716fd348SMartin Matuska print() 671716fd348SMartin Matuska 672716fd348SMartin Matuska print('ARC misc:') 673ce4dcb97SMartin Matuska prt_i1('Memory throttles:', arc_stats['memory_throttle_count']) 674ce4dcb97SMartin Matuska prt_i1('Memory direct reclaims:', arc_stats['memory_direct_count']) 675ce4dcb97SMartin Matuska prt_i1('Memory indirect reclaims:', arc_stats['memory_indirect_count']) 676716fd348SMartin Matuska prt_i1('Deleted:', f_hits(arc_stats['deleted'])) 677716fd348SMartin Matuska prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss'])) 678716fd348SMartin Matuska prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip'])) 679716fd348SMartin Matuska prt_i1('Eviction skips due to L2 writes:', 680716fd348SMartin Matuska f_hits(arc_stats['evict_l2_skip'])) 681716fd348SMartin Matuska prt_i1('L2 cached evictions:', f_bytes(arc_stats['evict_l2_cached'])) 682716fd348SMartin Matuska prt_i1('L2 eligible evictions:', f_bytes(arc_stats['evict_l2_eligible'])) 683716fd348SMartin Matuska prt_i2('L2 eligible MFU evictions:', 684716fd348SMartin Matuska f_perc(arc_stats['evict_l2_eligible_mfu'], 685716fd348SMartin Matuska arc_stats['evict_l2_eligible']), 686716fd348SMartin Matuska f_bytes(arc_stats['evict_l2_eligible_mfu'])) 687716fd348SMartin Matuska prt_i2('L2 eligible MRU evictions:', 688716fd348SMartin Matuska f_perc(arc_stats['evict_l2_eligible_mru'], 689716fd348SMartin Matuska arc_stats['evict_l2_eligible']), 690716fd348SMartin Matuska f_bytes(arc_stats['evict_l2_eligible_mru'])) 691716fd348SMartin Matuska prt_i1('L2 ineligible evictions:', 692716fd348SMartin Matuska f_bytes(arc_stats['evict_l2_ineligible'])) 693716fd348SMartin Matuska print() 694716fd348SMartin Matuska 695716fd348SMartin Matuska 696716fd348SMartin Matuskadef section_archits(kstats_dict): 697716fd348SMartin Matuska """Print information on how the caches are accessed ("arc hits"). 698716fd348SMartin Matuska """ 699716fd348SMartin Matuska 700716fd348SMartin Matuska arc_stats = isolate_section('arcstats', kstats_dict) 70115f0b8c3SMartin Matuska all_accesses = int(arc_stats['hits'])+int(arc_stats['iohits'])+\ 70215f0b8c3SMartin Matuska int(arc_stats['misses']) 703716fd348SMartin Matuska 70415f0b8c3SMartin Matuska prt_1('ARC total accesses:', f_hits(all_accesses)) 70515f0b8c3SMartin Matuska ta_todo = (('Total hits:', arc_stats['hits']), 70615f0b8c3SMartin Matuska ('Total I/O hits:', arc_stats['iohits']), 70715f0b8c3SMartin Matuska ('Total misses:', arc_stats['misses'])) 708716fd348SMartin Matuska for title, value in ta_todo: 709716fd348SMartin Matuska prt_i2(title, f_perc(value, all_accesses), f_hits(value)) 71015f0b8c3SMartin Matuska print() 711716fd348SMartin Matuska 712716fd348SMartin Matuska dd_total = int(arc_stats['demand_data_hits']) +\ 71315f0b8c3SMartin Matuska int(arc_stats['demand_data_iohits']) +\ 714716fd348SMartin Matuska int(arc_stats['demand_data_misses']) 71515f0b8c3SMartin Matuska prt_2('ARC demand data accesses:', f_perc(dd_total, all_accesses), 716716fd348SMartin Matuska f_hits(dd_total)) 71715f0b8c3SMartin Matuska dd_todo = (('Demand data hits:', arc_stats['demand_data_hits']), 71815f0b8c3SMartin Matuska ('Demand data I/O hits:', arc_stats['demand_data_iohits']), 71915f0b8c3SMartin Matuska ('Demand data misses:', arc_stats['demand_data_misses'])) 72015f0b8c3SMartin Matuska for title, value in dd_todo: 72115f0b8c3SMartin Matuska prt_i2(title, f_perc(value, dd_total), f_hits(value)) 722716fd348SMartin Matuska print() 72315f0b8c3SMartin Matuska 72415f0b8c3SMartin Matuska dm_total = int(arc_stats['demand_metadata_hits']) +\ 72515f0b8c3SMartin Matuska int(arc_stats['demand_metadata_iohits']) +\ 72615f0b8c3SMartin Matuska int(arc_stats['demand_metadata_misses']) 72715f0b8c3SMartin Matuska prt_2('ARC demand metadata accesses:', f_perc(dm_total, all_accesses), 72815f0b8c3SMartin Matuska f_hits(dm_total)) 72915f0b8c3SMartin Matuska dm_todo = (('Demand metadata hits:', arc_stats['demand_metadata_hits']), 73015f0b8c3SMartin Matuska ('Demand metadata I/O hits:', 73115f0b8c3SMartin Matuska arc_stats['demand_metadata_iohits']), 73215f0b8c3SMartin Matuska ('Demand metadata misses:', arc_stats['demand_metadata_misses'])) 73315f0b8c3SMartin Matuska for title, value in dm_todo: 73415f0b8c3SMartin Matuska prt_i2(title, f_perc(value, dm_total), f_hits(value)) 73515f0b8c3SMartin Matuska print() 73615f0b8c3SMartin Matuska 73715f0b8c3SMartin Matuska pd_total = int(arc_stats['prefetch_data_hits']) +\ 73815f0b8c3SMartin Matuska int(arc_stats['prefetch_data_iohits']) +\ 73915f0b8c3SMartin Matuska int(arc_stats['prefetch_data_misses']) 7406c1e79dfSMartin Matuska prt_2('ARC prefetch data accesses:', f_perc(pd_total, all_accesses), 74115f0b8c3SMartin Matuska f_hits(pd_total)) 74215f0b8c3SMartin Matuska pd_todo = (('Prefetch data hits:', arc_stats['prefetch_data_hits']), 74315f0b8c3SMartin Matuska ('Prefetch data I/O hits:', arc_stats['prefetch_data_iohits']), 74415f0b8c3SMartin Matuska ('Prefetch data misses:', arc_stats['prefetch_data_misses'])) 74515f0b8c3SMartin Matuska for title, value in pd_todo: 74615f0b8c3SMartin Matuska prt_i2(title, f_perc(value, pd_total), f_hits(value)) 74715f0b8c3SMartin Matuska print() 74815f0b8c3SMartin Matuska 74915f0b8c3SMartin Matuska pm_total = int(arc_stats['prefetch_metadata_hits']) +\ 75015f0b8c3SMartin Matuska int(arc_stats['prefetch_metadata_iohits']) +\ 75115f0b8c3SMartin Matuska int(arc_stats['prefetch_metadata_misses']) 75215f0b8c3SMartin Matuska prt_2('ARC prefetch metadata accesses:', f_perc(pm_total, all_accesses), 75315f0b8c3SMartin Matuska f_hits(pm_total)) 75415f0b8c3SMartin Matuska pm_todo = (('Prefetch metadata hits:', 75515f0b8c3SMartin Matuska arc_stats['prefetch_metadata_hits']), 75615f0b8c3SMartin Matuska ('Prefetch metadata I/O hits:', 75715f0b8c3SMartin Matuska arc_stats['prefetch_metadata_iohits']), 75815f0b8c3SMartin Matuska ('Prefetch metadata misses:', 75915f0b8c3SMartin Matuska arc_stats['prefetch_metadata_misses'])) 76015f0b8c3SMartin Matuska for title, value in pm_todo: 76115f0b8c3SMartin Matuska prt_i2(title, f_perc(value, pm_total), f_hits(value)) 76215f0b8c3SMartin Matuska print() 76315f0b8c3SMartin Matuska 76415f0b8c3SMartin Matuska all_prefetches = int(arc_stats['predictive_prefetch'])+\ 76515f0b8c3SMartin Matuska int(arc_stats['prescient_prefetch']) 76615f0b8c3SMartin Matuska prt_2('ARC predictive prefetches:', 76715f0b8c3SMartin Matuska f_perc(arc_stats['predictive_prefetch'], all_prefetches), 76815f0b8c3SMartin Matuska f_hits(arc_stats['predictive_prefetch'])) 76915f0b8c3SMartin Matuska prt_i2('Demand hits after predictive:', 77015f0b8c3SMartin Matuska f_perc(arc_stats['demand_hit_predictive_prefetch'], 77115f0b8c3SMartin Matuska arc_stats['predictive_prefetch']), 77215f0b8c3SMartin Matuska f_hits(arc_stats['demand_hit_predictive_prefetch'])) 77315f0b8c3SMartin Matuska prt_i2('Demand I/O hits after predictive:', 77415f0b8c3SMartin Matuska f_perc(arc_stats['demand_iohit_predictive_prefetch'], 77515f0b8c3SMartin Matuska arc_stats['predictive_prefetch']), 77615f0b8c3SMartin Matuska f_hits(arc_stats['demand_iohit_predictive_prefetch'])) 77715f0b8c3SMartin Matuska never = int(arc_stats['predictive_prefetch']) -\ 77815f0b8c3SMartin Matuska int(arc_stats['demand_hit_predictive_prefetch']) -\ 77915f0b8c3SMartin Matuska int(arc_stats['demand_iohit_predictive_prefetch']) 78015f0b8c3SMartin Matuska prt_i2('Never demanded after predictive:', 78115f0b8c3SMartin Matuska f_perc(never, arc_stats['predictive_prefetch']), 78215f0b8c3SMartin Matuska f_hits(never)) 78315f0b8c3SMartin Matuska print() 78415f0b8c3SMartin Matuska 78515f0b8c3SMartin Matuska prt_2('ARC prescient prefetches:', 78615f0b8c3SMartin Matuska f_perc(arc_stats['prescient_prefetch'], all_prefetches), 78715f0b8c3SMartin Matuska f_hits(arc_stats['prescient_prefetch'])) 78815f0b8c3SMartin Matuska prt_i2('Demand hits after prescient:', 78915f0b8c3SMartin Matuska f_perc(arc_stats['demand_hit_prescient_prefetch'], 79015f0b8c3SMartin Matuska arc_stats['prescient_prefetch']), 79115f0b8c3SMartin Matuska f_hits(arc_stats['demand_hit_prescient_prefetch'])) 79215f0b8c3SMartin Matuska prt_i2('Demand I/O hits after prescient:', 79315f0b8c3SMartin Matuska f_perc(arc_stats['demand_iohit_prescient_prefetch'], 79415f0b8c3SMartin Matuska arc_stats['prescient_prefetch']), 79515f0b8c3SMartin Matuska f_hits(arc_stats['demand_iohit_prescient_prefetch'])) 79615f0b8c3SMartin Matuska never = int(arc_stats['prescient_prefetch'])-\ 79715f0b8c3SMartin Matuska int(arc_stats['demand_hit_prescient_prefetch'])-\ 79815f0b8c3SMartin Matuska int(arc_stats['demand_iohit_prescient_prefetch']) 79915f0b8c3SMartin Matuska prt_i2('Never demanded after prescient:', 80015f0b8c3SMartin Matuska f_perc(never, arc_stats['prescient_prefetch']), 80115f0b8c3SMartin Matuska f_hits(never)) 80215f0b8c3SMartin Matuska print() 80315f0b8c3SMartin Matuska 80415f0b8c3SMartin Matuska print('ARC states hits of all accesses:') 805716fd348SMartin Matuska cl_todo = (('Most frequently used (MFU):', arc_stats['mfu_hits']), 806716fd348SMartin Matuska ('Most recently used (MRU):', arc_stats['mru_hits']), 807716fd348SMartin Matuska ('Most frequently used (MFU) ghost:', 808716fd348SMartin Matuska arc_stats['mfu_ghost_hits']), 809716fd348SMartin Matuska ('Most recently used (MRU) ghost:', 81015f0b8c3SMartin Matuska arc_stats['mru_ghost_hits']), 81115f0b8c3SMartin Matuska ('Uncached:', arc_stats['uncached_hits'])) 812716fd348SMartin Matuska for title, value in cl_todo: 81315f0b8c3SMartin Matuska prt_i2(title, f_perc(value, all_accesses), f_hits(value)) 814716fd348SMartin Matuska print() 815716fd348SMartin Matuska 816716fd348SMartin Matuska 817716fd348SMartin Matuskadef section_dmu(kstats_dict): 818716fd348SMartin Matuska """Collect information on the DMU""" 819716fd348SMartin Matuska 820716fd348SMartin Matuska zfetch_stats = isolate_section('zfetchstats', kstats_dict) 821716fd348SMartin Matuska 8221719886fSMartin Matuska zfetch_access_total = int(zfetch_stats['hits']) +\ 8231719886fSMartin Matuska int(zfetch_stats['future']) + int(zfetch_stats['stride']) +\ 8241719886fSMartin Matuska int(zfetch_stats['past']) + int(zfetch_stats['misses']) 825716fd348SMartin Matuska 82615f0b8c3SMartin Matuska prt_1('DMU predictive prefetcher calls:', f_hits(zfetch_access_total)) 82715f0b8c3SMartin Matuska prt_i2('Stream hits:', 82815f0b8c3SMartin Matuska f_perc(zfetch_stats['hits'], zfetch_access_total), 829716fd348SMartin Matuska f_hits(zfetch_stats['hits'])) 8301719886fSMartin Matuska future = int(zfetch_stats['future']) + int(zfetch_stats['stride']) 8311719886fSMartin Matuska prt_i2('Hits ahead of stream:', f_perc(future, zfetch_access_total), 8321719886fSMartin Matuska f_hits(future)) 8331719886fSMartin Matuska prt_i2('Hits behind stream:', 8341719886fSMartin Matuska f_perc(zfetch_stats['past'], zfetch_access_total), 8351719886fSMartin Matuska f_hits(zfetch_stats['past'])) 83615f0b8c3SMartin Matuska prt_i2('Stream misses:', 83715f0b8c3SMartin Matuska f_perc(zfetch_stats['misses'], zfetch_access_total), 838716fd348SMartin Matuska f_hits(zfetch_stats['misses'])) 83915f0b8c3SMartin Matuska prt_i2('Streams limit reached:', 84015f0b8c3SMartin Matuska f_perc(zfetch_stats['max_streams'], zfetch_stats['misses']), 84115f0b8c3SMartin Matuska f_hits(zfetch_stats['max_streams'])) 8421719886fSMartin Matuska prt_i1('Stream strides:', f_hits(zfetch_stats['stride'])) 84315f0b8c3SMartin Matuska prt_i1('Prefetches issued', f_hits(zfetch_stats['io_issued'])) 844716fd348SMartin Matuska print() 845716fd348SMartin Matuska 846716fd348SMartin Matuska 847716fd348SMartin Matuskadef section_l2arc(kstats_dict): 848716fd348SMartin Matuska """Collect information on L2ARC device if present. If not, tell user 849716fd348SMartin Matuska that we're skipping the section. 850716fd348SMartin Matuska """ 851716fd348SMartin Matuska 852716fd348SMartin Matuska # The L2ARC statistics live in the same section as the normal ARC stuff 853716fd348SMartin Matuska arc_stats = isolate_section('arcstats', kstats_dict) 854716fd348SMartin Matuska 855716fd348SMartin Matuska if arc_stats['l2_size'] == '0': 856716fd348SMartin Matuska print('L2ARC not detected, skipping section\n') 857716fd348SMartin Matuska return 858716fd348SMartin Matuska 859716fd348SMartin Matuska l2_errors = int(arc_stats['l2_writes_error']) +\ 860716fd348SMartin Matuska int(arc_stats['l2_cksum_bad']) +\ 861716fd348SMartin Matuska int(arc_stats['l2_io_error']) 862716fd348SMartin Matuska 863716fd348SMartin Matuska l2_access_total = int(arc_stats['l2_hits'])+int(arc_stats['l2_misses']) 864716fd348SMartin Matuska health = 'HEALTHY' 865716fd348SMartin Matuska 866716fd348SMartin Matuska if l2_errors > 0: 867716fd348SMartin Matuska health = 'DEGRADED' 868716fd348SMartin Matuska 869716fd348SMartin Matuska prt_1('L2ARC status:', health) 870716fd348SMartin Matuska 871716fd348SMartin Matuska l2_todo = (('Low memory aborts:', 'l2_abort_lowmem'), 872716fd348SMartin Matuska ('Free on write:', 'l2_free_on_write'), 873716fd348SMartin Matuska ('R/W clashes:', 'l2_rw_clash'), 874716fd348SMartin Matuska ('Bad checksums:', 'l2_cksum_bad'), 8754e8d558cSMartin Matuska ('Read errors:', 'l2_io_error'), 8764e8d558cSMartin Matuska ('Write errors:', 'l2_writes_error')) 877716fd348SMartin Matuska 878716fd348SMartin Matuska for title, value in l2_todo: 879716fd348SMartin Matuska prt_i1(title, f_hits(arc_stats[value])) 880716fd348SMartin Matuska 881716fd348SMartin Matuska print() 882716fd348SMartin Matuska prt_1('L2ARC size (adaptive):', f_bytes(arc_stats['l2_size'])) 883716fd348SMartin Matuska prt_i2('Compressed:', f_perc(arc_stats['l2_asize'], arc_stats['l2_size']), 884716fd348SMartin Matuska f_bytes(arc_stats['l2_asize'])) 885716fd348SMartin Matuska prt_i2('Header size:', 886716fd348SMartin Matuska f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']), 887716fd348SMartin Matuska f_bytes(arc_stats['l2_hdr_size'])) 888716fd348SMartin Matuska prt_i2('MFU allocated size:', 889716fd348SMartin Matuska f_perc(arc_stats['l2_mfu_asize'], arc_stats['l2_asize']), 890716fd348SMartin Matuska f_bytes(arc_stats['l2_mfu_asize'])) 891716fd348SMartin Matuska prt_i2('MRU allocated size:', 892716fd348SMartin Matuska f_perc(arc_stats['l2_mru_asize'], arc_stats['l2_asize']), 893716fd348SMartin Matuska f_bytes(arc_stats['l2_mru_asize'])) 894716fd348SMartin Matuska prt_i2('Prefetch allocated size:', 895716fd348SMartin Matuska f_perc(arc_stats['l2_prefetch_asize'], arc_stats['l2_asize']), 896716fd348SMartin Matuska f_bytes(arc_stats['l2_prefetch_asize'])) 897716fd348SMartin Matuska prt_i2('Data (buffer content) allocated size:', 898716fd348SMartin Matuska f_perc(arc_stats['l2_bufc_data_asize'], arc_stats['l2_asize']), 899716fd348SMartin Matuska f_bytes(arc_stats['l2_bufc_data_asize'])) 900716fd348SMartin Matuska prt_i2('Metadata (buffer content) allocated size:', 901716fd348SMartin Matuska f_perc(arc_stats['l2_bufc_metadata_asize'], arc_stats['l2_asize']), 902716fd348SMartin Matuska f_bytes(arc_stats['l2_bufc_metadata_asize'])) 903716fd348SMartin Matuska 904716fd348SMartin Matuska print() 905716fd348SMartin Matuska prt_1('L2ARC breakdown:', f_hits(l2_access_total)) 906716fd348SMartin Matuska prt_i2('Hit ratio:', 907716fd348SMartin Matuska f_perc(arc_stats['l2_hits'], l2_access_total), 908716fd348SMartin Matuska f_hits(arc_stats['l2_hits'])) 909716fd348SMartin Matuska prt_i2('Miss ratio:', 910716fd348SMartin Matuska f_perc(arc_stats['l2_misses'], l2_access_total), 911716fd348SMartin Matuska f_hits(arc_stats['l2_misses'])) 912716fd348SMartin Matuska 913716fd348SMartin Matuska print() 9144e8d558cSMartin Matuska print('L2ARC I/O:') 9154e8d558cSMartin Matuska prt_i2('Reads:', 9164e8d558cSMartin Matuska f_bytes(arc_stats['l2_read_bytes']), 9174e8d558cSMartin Matuska f_hits(arc_stats['l2_hits'])) 9184e8d558cSMartin Matuska prt_i2('Writes:', 9194e8d558cSMartin Matuska f_bytes(arc_stats['l2_write_bytes']), 9204e8d558cSMartin Matuska f_hits(arc_stats['l2_writes_sent'])) 921716fd348SMartin Matuska 922716fd348SMartin Matuska print() 923716fd348SMartin Matuska print('L2ARC evicts:') 9244e8d558cSMartin Matuska prt_i1('L1 cached:', f_hits(arc_stats['l2_evict_l1cached'])) 9254e8d558cSMartin Matuska prt_i1('While reading:', f_hits(arc_stats['l2_evict_reading'])) 926716fd348SMartin Matuska print() 927716fd348SMartin Matuska 928716fd348SMartin Matuska 929716fd348SMartin Matuskadef section_spl(*_): 930716fd348SMartin Matuska """Print the SPL parameters, if requested with alternative format 931716fd348SMartin Matuska and/or descriptions. This does not use kstats. 932716fd348SMartin Matuska """ 933716fd348SMartin Matuska 934716fd348SMartin Matuska if sys.platform.startswith('freebsd'): 935716fd348SMartin Matuska # No SPL support in FreeBSD 936716fd348SMartin Matuska return 937716fd348SMartin Matuska 938716fd348SMartin Matuska spls = get_spl_params() 939716fd348SMartin Matuska keylist = sorted(spls.keys()) 940716fd348SMartin Matuska print('Solaris Porting Layer (SPL):') 941716fd348SMartin Matuska 942716fd348SMartin Matuska if ARGS.desc: 943716fd348SMartin Matuska descriptions = get_descriptions('spl') 944716fd348SMartin Matuska 945716fd348SMartin Matuska for key in keylist: 946716fd348SMartin Matuska value = spls[key] 947716fd348SMartin Matuska 948716fd348SMartin Matuska if ARGS.desc: 949716fd348SMartin Matuska try: 950716fd348SMartin Matuska print(INDENT+'#', descriptions[key]) 951716fd348SMartin Matuska except KeyError: 952716fd348SMartin Matuska print(INDENT+'# (No description found)') # paranoid 953716fd348SMartin Matuska 954716fd348SMartin Matuska print(format_raw_line(key, value)) 955716fd348SMartin Matuska 956716fd348SMartin Matuska print() 957716fd348SMartin Matuska 958716fd348SMartin Matuska 959716fd348SMartin Matuskadef section_tunables(*_): 960716fd348SMartin Matuska """Print the tunables, if requested with alternative format and/or 961716fd348SMartin Matuska descriptions. This does not use kstasts. 962716fd348SMartin Matuska """ 963716fd348SMartin Matuska 964716fd348SMartin Matuska tunables = get_tunable_params() 965716fd348SMartin Matuska keylist = sorted(tunables.keys()) 966716fd348SMartin Matuska print('Tunables:') 967716fd348SMartin Matuska 968716fd348SMartin Matuska if ARGS.desc: 969716fd348SMartin Matuska descriptions = get_descriptions('zfs') 970716fd348SMartin Matuska 971716fd348SMartin Matuska for key in keylist: 972716fd348SMartin Matuska value = tunables[key] 973716fd348SMartin Matuska 974716fd348SMartin Matuska if ARGS.desc: 975716fd348SMartin Matuska try: 976716fd348SMartin Matuska print(INDENT+'#', descriptions[key]) 977716fd348SMartin Matuska except KeyError: 978716fd348SMartin Matuska print(INDENT+'# (No description found)') # paranoid 979716fd348SMartin Matuska 980716fd348SMartin Matuska print(format_raw_line(key, value)) 981716fd348SMartin Matuska 982716fd348SMartin Matuska print() 983716fd348SMartin Matuska 984716fd348SMartin Matuska 985716fd348SMartin Matuskadef section_zil(kstats_dict): 986716fd348SMartin Matuska """Collect information on the ZFS Intent Log. Some of the information 987716fd348SMartin Matuska taken from https://github.com/openzfs/zfs/blob/master/include/sys/zil.h 988716fd348SMartin Matuska """ 989716fd348SMartin Matuska 990716fd348SMartin Matuska zil_stats = isolate_section('zil', kstats_dict) 991716fd348SMartin Matuska 992716fd348SMartin Matuska prt_1('ZIL committed transactions:', 993716fd348SMartin Matuska f_hits(zil_stats['zil_itx_count'])) 994716fd348SMartin Matuska prt_i1('Commit requests:', f_hits(zil_stats['zil_commit_count'])) 995716fd348SMartin Matuska prt_i1('Flushes to stable storage:', 996716fd348SMartin Matuska f_hits(zil_stats['zil_commit_writer_count'])) 997716fd348SMartin Matuska prt_i2('Transactions to SLOG storage pool:', 998716fd348SMartin Matuska f_bytes(zil_stats['zil_itx_metaslab_slog_bytes']), 999716fd348SMartin Matuska f_hits(zil_stats['zil_itx_metaslab_slog_count'])) 1000716fd348SMartin Matuska prt_i2('Transactions to non-SLOG storage pool:', 1001716fd348SMartin Matuska f_bytes(zil_stats['zil_itx_metaslab_normal_bytes']), 1002716fd348SMartin Matuska f_hits(zil_stats['zil_itx_metaslab_normal_count'])) 1003716fd348SMartin Matuska print() 1004716fd348SMartin Matuska 1005716fd348SMartin Matuska 1006716fd348SMartin Matuskasection_calls = {'arc': section_arc, 1007716fd348SMartin Matuska 'archits': section_archits, 1008716fd348SMartin Matuska 'dmu': section_dmu, 1009716fd348SMartin Matuska 'l2arc': section_l2arc, 1010716fd348SMartin Matuska 'spl': section_spl, 1011716fd348SMartin Matuska 'tunables': section_tunables, 1012716fd348SMartin Matuska 'zil': section_zil} 1013716fd348SMartin Matuska 1014716fd348SMartin Matuska 1015716fd348SMartin Matuskadef main(): 1016716fd348SMartin Matuska """Run program. The options to draw a graph and to print all data raw are 1017716fd348SMartin Matuska treated separately because they come with their own call. 1018716fd348SMartin Matuska """ 1019716fd348SMartin Matuska 1020716fd348SMartin Matuska kstats = get_kstats() 1021716fd348SMartin Matuska 1022716fd348SMartin Matuska if ARGS.graph: 1023716fd348SMartin Matuska draw_graph(kstats) 1024716fd348SMartin Matuska sys.exit(0) 1025716fd348SMartin Matuska 1026716fd348SMartin Matuska print_header() 1027716fd348SMartin Matuska 1028716fd348SMartin Matuska if ARGS.raw: 1029716fd348SMartin Matuska print_raw(kstats) 1030716fd348SMartin Matuska 1031716fd348SMartin Matuska elif ARGS.section: 1032716fd348SMartin Matuska 1033716fd348SMartin Matuska try: 1034716fd348SMartin Matuska section_calls[ARGS.section](kstats) 1035716fd348SMartin Matuska except KeyError: 1036716fd348SMartin Matuska print('Error: Section "{0}" unknown'.format(ARGS.section)) 1037716fd348SMartin Matuska sys.exit(1) 1038716fd348SMartin Matuska 1039716fd348SMartin Matuska elif ARGS.page: 1040716fd348SMartin Matuska print('WARNING: Pages are deprecated, please use "--section"\n') 1041716fd348SMartin Matuska 1042716fd348SMartin Matuska pages_to_calls = {1: 'arc', 1043716fd348SMartin Matuska 2: 'archits', 1044716fd348SMartin Matuska 3: 'l2arc', 1045716fd348SMartin Matuska 4: 'dmu', 1046716fd348SMartin Matuska 5: 'vdev', 1047716fd348SMartin Matuska 6: 'tunables'} 1048716fd348SMartin Matuska 1049716fd348SMartin Matuska try: 1050716fd348SMartin Matuska call = pages_to_calls[ARGS.page] 1051716fd348SMartin Matuska except KeyError: 1052716fd348SMartin Matuska print('Error: Page "{0}" not supported'.format(ARGS.page)) 1053716fd348SMartin Matuska sys.exit(1) 1054716fd348SMartin Matuska else: 1055716fd348SMartin Matuska section_calls[call](kstats) 1056716fd348SMartin Matuska 1057716fd348SMartin Matuska else: 1058716fd348SMartin Matuska # If no parameters were given, we print all sections. We might want to 1059716fd348SMartin Matuska # change the sequence by hand 1060716fd348SMartin Matuska calls = sorted(section_calls.keys()) 1061716fd348SMartin Matuska 1062716fd348SMartin Matuska for section in calls: 1063716fd348SMartin Matuska section_calls[section](kstats) 1064716fd348SMartin Matuska 1065716fd348SMartin Matuska sys.exit(0) 1066716fd348SMartin Matuska 1067716fd348SMartin Matuska 1068716fd348SMartin Matuskaif __name__ == '__main__': 1069716fd348SMartin Matuska main() 1070