xref: /freebsd/sys/contrib/openzfs/cmd/arc_summary (revision ce4dcb97ca433b2a2f03fbae957dae0ff16f6f51)
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
263*ce4dcb97SMartin Matuska    GRAPH_WIDTH = 70
264*ce4dcb97SMartin Matuska    arc_max = int(arc_stats['c_max'])
265716fd348SMartin Matuska    arc_size = f_bytes(arc_stats['size'])
266*ce4dcb97SMartin Matuska    arc_perc = f_perc(arc_stats['size'], arc_max)
267*ce4dcb97SMartin Matuska    data_size = f_bytes(arc_stats['data_size'])
268*ce4dcb97SMartin Matuska    meta_size = f_bytes(arc_stats['metadata_size'])
269716fd348SMartin Matuska    dnode_size = f_bytes(arc_stats['dnode_size'])
270716fd348SMartin Matuska
271*ce4dcb97SMartin Matuska    info_form = ('ARC: {0} ({1}) Data: {2} Meta: {3} Dnode: {4}')
272*ce4dcb97SMartin Matuska    info_line = info_form.format(arc_size, arc_perc, data_size, meta_size,
273*ce4dcb97SMartin 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
279*ce4dcb97SMartin Matuska    arc_perc = float(int(arc_stats['size'])/arc_max)
280*ce4dcb97SMartin Matuska    data_perc = float(int(arc_stats['data_size'])/arc_max)
281*ce4dcb97SMartin Matuska    meta_perc = float(int(arc_stats['metadata_size'])/arc_max)
282*ce4dcb97SMartin Matuska    dnode_perc = float(int(arc_stats['dnode_size'])/arc_max)
283716fd348SMartin Matuska    total_ticks = float(arc_perc)*GRAPH_WIDTH
284*ce4dcb97SMartin Matuska    data_ticks = data_perc*GRAPH_WIDTH
285*ce4dcb97SMartin Matuska    meta_ticks = meta_perc*GRAPH_WIDTH
286*ce4dcb97SMartin Matuska    dnode_ticks = dnode_perc*GRAPH_WIDTH
287*ce4dcb97SMartin Matuska    other_ticks = total_ticks-(data_ticks+meta_ticks+dnode_ticks)
288716fd348SMartin Matuska
289*ce4dcb97SMartin Matuska    core_form = 'D'*int(data_ticks)+'M'*int(meta_ticks)+'N'*int(dnode_ticks)+\
290*ce4dcb97SMartin 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
540*ce4dcb97SMartin Matuska    memory_all = arc_stats['memory_all_bytes']
541*ce4dcb97SMartin Matuska    memory_free = arc_stats['memory_free_bytes']
542*ce4dcb97SMartin 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']
547*ce4dcb97SMartin Matuska    dnode_limit = arc_stats['arc_dnode_limit']
548*ce4dcb97SMartin Matuska
549*ce4dcb97SMartin Matuska    print('ARC status:')
550*ce4dcb97SMartin Matuska    prt_i1('Total memory size:', f_bytes(memory_all))
551*ce4dcb97SMartin Matuska    prt_i2('Min target size:', f_perc(arc_min, memory_all), f_bytes(arc_min))
552*ce4dcb97SMartin Matuska    prt_i2('Max target size:', f_perc(arc_max, memory_all), f_bytes(arc_max))
553*ce4dcb97SMartin Matuska    prt_i2('Target size (adaptive):',
554*ce4dcb97SMartin Matuska           f_perc(arc_size, arc_max), f_bytes(arc_target_size))
555*ce4dcb97SMartin Matuska    prt_i2('Current size:', f_perc(arc_size, arc_max), f_bytes(arc_size))
556*ce4dcb97SMartin Matuska    prt_i1('Free memory size:', f_bytes(memory_free))
557*ce4dcb97SMartin Matuska    prt_i1('Available memory size:', f_bytes(memory_avail))
558*ce4dcb97SMartin Matuska    print()
559*ce4dcb97SMartin Matuska
560*ce4dcb97SMartin Matuska    compressed_size = arc_stats['compressed_size']
561*ce4dcb97SMartin Matuska    overhead_size = arc_stats['overhead_size']
562*ce4dcb97SMartin Matuska    bonus_size = arc_stats['bonus_size']
563*ce4dcb97SMartin Matuska    dnode_size = arc_stats['dnode_size']
564*ce4dcb97SMartin Matuska    dbuf_size = arc_stats['dbuf_size']
565*ce4dcb97SMartin Matuska    hdr_size = arc_stats['hdr_size']
566*ce4dcb97SMartin Matuska    l2_hdr_size = arc_stats['l2_hdr_size']
567*ce4dcb97SMartin Matuska    abd_chunk_waste_size = arc_stats['abd_chunk_waste_size']
568*ce4dcb97SMartin Matuska
569*ce4dcb97SMartin Matuska    prt_1('ARC structal breakdown (current size):', f_bytes(arc_size))
570*ce4dcb97SMartin Matuska    prt_i2('Compressed size:',
571*ce4dcb97SMartin Matuska           f_perc(compressed_size, arc_size), f_bytes(compressed_size))
572*ce4dcb97SMartin Matuska    prt_i2('Overhead size:',
573*ce4dcb97SMartin Matuska           f_perc(overhead_size, arc_size), f_bytes(overhead_size))
574*ce4dcb97SMartin Matuska    prt_i2('Bonus size:',
575*ce4dcb97SMartin Matuska           f_perc(bonus_size, arc_size), f_bytes(bonus_size))
576*ce4dcb97SMartin Matuska    prt_i2('Dnode size:',
577*ce4dcb97SMartin Matuska           f_perc(dnode_size, arc_size), f_bytes(dnode_size))
578*ce4dcb97SMartin Matuska    prt_i2('Dbuf size:',
579*ce4dcb97SMartin Matuska           f_perc(dbuf_size, arc_size), f_bytes(dbuf_size))
580*ce4dcb97SMartin Matuska    prt_i2('Header size:',
581*ce4dcb97SMartin Matuska           f_perc(hdr_size, arc_size), f_bytes(hdr_size))
582*ce4dcb97SMartin Matuska    prt_i2('L2 header size:',
583*ce4dcb97SMartin Matuska           f_perc(l2_hdr_size, arc_size), f_bytes(l2_hdr_size))
584*ce4dcb97SMartin Matuska    prt_i2('ABD chunk waste size:',
585*ce4dcb97SMartin Matuska           f_perc(abd_chunk_waste_size, arc_size), f_bytes(abd_chunk_waste_size))
586*ce4dcb97SMartin Matuska    print()
587*ce4dcb97SMartin Matuska
5882a58b312SMartin Matuska    meta = arc_stats['meta']
5892a58b312SMartin Matuska    pd = arc_stats['pd']
5902a58b312SMartin Matuska    pm = arc_stats['pm']
591*ce4dcb97SMartin Matuska    data_size = arc_stats['data_size']
592*ce4dcb97SMartin 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']
597*ce4dcb97SMartin Matuska    mfu_edata = arc_stats['mfu_evictable_data']
598*ce4dcb97SMartin Matuska    mfu_emetadata = arc_stats['mfu_evictable_metadata']
5992a58b312SMartin Matuska    mru_data = arc_stats['mru_data']
6002a58b312SMartin Matuska    mru_metadata = arc_stats['mru_metadata']
601*ce4dcb97SMartin Matuska    mru_edata = arc_stats['mru_evictable_data']
602*ce4dcb97SMartin 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)
612*ce4dcb97SMartin Matuska
613*ce4dcb97SMartin Matuska    prt_1('ARC types breakdown (compressed + overhead):', f_bytes(caches_size))
614*ce4dcb97SMartin Matuska    prt_i2('Data size:',
615*ce4dcb97SMartin Matuska           f_perc(data_size, caches_size), f_bytes(data_size))
616*ce4dcb97SMartin Matuska    prt_i2('Metadata size:',
617*ce4dcb97SMartin Matuska           f_perc(metadata_size, caches_size), f_bytes(metadata_size))
618*ce4dcb97SMartin Matuska    print()
619*ce4dcb97SMartin Matuska
620*ce4dcb97SMartin 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))
631*ce4dcb97SMartin Matuska    prt_i2('MFU evictable data size:',
632*ce4dcb97SMartin 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))
639*ce4dcb97SMartin Matuska    prt_i2('MFU evictable metadata size:',
640*ce4dcb97SMartin 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))
647*ce4dcb97SMartin Matuska    prt_i2('MRU evictable data size:',
648*ce4dcb97SMartin 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))
655*ce4dcb97SMartin Matuska    prt_i2('MRU evictable metadata size:',
656*ce4dcb97SMartin 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:')
665716fd348SMartin Matuska    prt_i1('Elements max:', f_hits(arc_stats['hash_elements_max']))
666716fd348SMartin Matuska    prt_i2('Elements current:',
667716fd348SMartin Matuska           f_perc(arc_stats['hash_elements'], arc_stats['hash_elements_max']),
668716fd348SMartin Matuska           f_hits(arc_stats['hash_elements']))
669716fd348SMartin Matuska    prt_i1('Collisions:', f_hits(arc_stats['hash_collisions']))
670716fd348SMartin Matuska
671716fd348SMartin Matuska    prt_i1('Chain max:', f_hits(arc_stats['hash_chain_max']))
672716fd348SMartin Matuska    prt_i1('Chains:', f_hits(arc_stats['hash_chains']))
673716fd348SMartin Matuska    print()
674716fd348SMartin Matuska
675716fd348SMartin Matuska    print('ARC misc:')
676*ce4dcb97SMartin Matuska    prt_i1('Memory throttles:', arc_stats['memory_throttle_count'])
677*ce4dcb97SMartin Matuska    prt_i1('Memory direct reclaims:', arc_stats['memory_direct_count'])
678*ce4dcb97SMartin Matuska    prt_i1('Memory indirect reclaims:', arc_stats['memory_indirect_count'])
679716fd348SMartin Matuska    prt_i1('Deleted:', f_hits(arc_stats['deleted']))
680716fd348SMartin Matuska    prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss']))
681716fd348SMartin Matuska    prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip']))
682716fd348SMartin Matuska    prt_i1('Eviction skips due to L2 writes:',
683716fd348SMartin Matuska           f_hits(arc_stats['evict_l2_skip']))
684716fd348SMartin Matuska    prt_i1('L2 cached evictions:', f_bytes(arc_stats['evict_l2_cached']))
685716fd348SMartin Matuska    prt_i1('L2 eligible evictions:', f_bytes(arc_stats['evict_l2_eligible']))
686716fd348SMartin Matuska    prt_i2('L2 eligible MFU evictions:',
687716fd348SMartin Matuska           f_perc(arc_stats['evict_l2_eligible_mfu'],
688716fd348SMartin Matuska           arc_stats['evict_l2_eligible']),
689716fd348SMartin Matuska           f_bytes(arc_stats['evict_l2_eligible_mfu']))
690716fd348SMartin Matuska    prt_i2('L2 eligible MRU evictions:',
691716fd348SMartin Matuska           f_perc(arc_stats['evict_l2_eligible_mru'],
692716fd348SMartin Matuska           arc_stats['evict_l2_eligible']),
693716fd348SMartin Matuska           f_bytes(arc_stats['evict_l2_eligible_mru']))
694716fd348SMartin Matuska    prt_i1('L2 ineligible evictions:',
695716fd348SMartin Matuska           f_bytes(arc_stats['evict_l2_ineligible']))
696716fd348SMartin Matuska    print()
697716fd348SMartin Matuska
698716fd348SMartin Matuska
699716fd348SMartin Matuskadef section_archits(kstats_dict):
700716fd348SMartin Matuska    """Print information on how the caches are accessed ("arc hits").
701716fd348SMartin Matuska    """
702716fd348SMartin Matuska
703716fd348SMartin Matuska    arc_stats = isolate_section('arcstats', kstats_dict)
70415f0b8c3SMartin Matuska    all_accesses = int(arc_stats['hits'])+int(arc_stats['iohits'])+\
70515f0b8c3SMartin Matuska        int(arc_stats['misses'])
706716fd348SMartin Matuska
70715f0b8c3SMartin Matuska    prt_1('ARC total accesses:', f_hits(all_accesses))
70815f0b8c3SMartin Matuska    ta_todo = (('Total hits:', arc_stats['hits']),
70915f0b8c3SMartin Matuska               ('Total I/O hits:', arc_stats['iohits']),
71015f0b8c3SMartin Matuska               ('Total misses:', arc_stats['misses']))
711716fd348SMartin Matuska    for title, value in ta_todo:
712716fd348SMartin Matuska        prt_i2(title, f_perc(value, all_accesses), f_hits(value))
71315f0b8c3SMartin Matuska    print()
714716fd348SMartin Matuska
715716fd348SMartin Matuska    dd_total = int(arc_stats['demand_data_hits']) +\
71615f0b8c3SMartin Matuska        int(arc_stats['demand_data_iohits']) +\
717716fd348SMartin Matuska        int(arc_stats['demand_data_misses'])
71815f0b8c3SMartin Matuska    prt_2('ARC demand data accesses:', f_perc(dd_total, all_accesses),
719716fd348SMartin Matuska         f_hits(dd_total))
72015f0b8c3SMartin Matuska    dd_todo = (('Demand data hits:', arc_stats['demand_data_hits']),
72115f0b8c3SMartin Matuska               ('Demand data I/O hits:', arc_stats['demand_data_iohits']),
72215f0b8c3SMartin Matuska               ('Demand data misses:', arc_stats['demand_data_misses']))
72315f0b8c3SMartin Matuska    for title, value in dd_todo:
72415f0b8c3SMartin Matuska        prt_i2(title, f_perc(value, dd_total), f_hits(value))
725716fd348SMartin Matuska    print()
72615f0b8c3SMartin Matuska
72715f0b8c3SMartin Matuska    dm_total = int(arc_stats['demand_metadata_hits']) +\
72815f0b8c3SMartin Matuska        int(arc_stats['demand_metadata_iohits']) +\
72915f0b8c3SMartin Matuska        int(arc_stats['demand_metadata_misses'])
73015f0b8c3SMartin Matuska    prt_2('ARC demand metadata accesses:', f_perc(dm_total, all_accesses),
73115f0b8c3SMartin Matuska          f_hits(dm_total))
73215f0b8c3SMartin Matuska    dm_todo = (('Demand metadata hits:', arc_stats['demand_metadata_hits']),
73315f0b8c3SMartin Matuska               ('Demand metadata I/O hits:',
73415f0b8c3SMartin Matuska                arc_stats['demand_metadata_iohits']),
73515f0b8c3SMartin Matuska               ('Demand metadata misses:', arc_stats['demand_metadata_misses']))
73615f0b8c3SMartin Matuska    for title, value in dm_todo:
73715f0b8c3SMartin Matuska        prt_i2(title, f_perc(value, dm_total), f_hits(value))
73815f0b8c3SMartin Matuska    print()
73915f0b8c3SMartin Matuska
74015f0b8c3SMartin Matuska    pd_total = int(arc_stats['prefetch_data_hits']) +\
74115f0b8c3SMartin Matuska        int(arc_stats['prefetch_data_iohits']) +\
74215f0b8c3SMartin Matuska        int(arc_stats['prefetch_data_misses'])
7436c1e79dfSMartin Matuska    prt_2('ARC prefetch data accesses:', f_perc(pd_total, all_accesses),
74415f0b8c3SMartin Matuska          f_hits(pd_total))
74515f0b8c3SMartin Matuska    pd_todo = (('Prefetch data hits:', arc_stats['prefetch_data_hits']),
74615f0b8c3SMartin Matuska               ('Prefetch data I/O hits:', arc_stats['prefetch_data_iohits']),
74715f0b8c3SMartin Matuska               ('Prefetch data misses:', arc_stats['prefetch_data_misses']))
74815f0b8c3SMartin Matuska    for title, value in pd_todo:
74915f0b8c3SMartin Matuska        prt_i2(title, f_perc(value, pd_total), f_hits(value))
75015f0b8c3SMartin Matuska    print()
75115f0b8c3SMartin Matuska
75215f0b8c3SMartin Matuska    pm_total = int(arc_stats['prefetch_metadata_hits']) +\
75315f0b8c3SMartin Matuska        int(arc_stats['prefetch_metadata_iohits']) +\
75415f0b8c3SMartin Matuska        int(arc_stats['prefetch_metadata_misses'])
75515f0b8c3SMartin Matuska    prt_2('ARC prefetch metadata accesses:', f_perc(pm_total, all_accesses),
75615f0b8c3SMartin Matuska          f_hits(pm_total))
75715f0b8c3SMartin Matuska    pm_todo = (('Prefetch metadata hits:',
75815f0b8c3SMartin Matuska                arc_stats['prefetch_metadata_hits']),
75915f0b8c3SMartin Matuska               ('Prefetch metadata I/O hits:',
76015f0b8c3SMartin Matuska                arc_stats['prefetch_metadata_iohits']),
76115f0b8c3SMartin Matuska               ('Prefetch metadata misses:',
76215f0b8c3SMartin Matuska                arc_stats['prefetch_metadata_misses']))
76315f0b8c3SMartin Matuska    for title, value in pm_todo:
76415f0b8c3SMartin Matuska        prt_i2(title, f_perc(value, pm_total), f_hits(value))
76515f0b8c3SMartin Matuska    print()
76615f0b8c3SMartin Matuska
76715f0b8c3SMartin Matuska    all_prefetches = int(arc_stats['predictive_prefetch'])+\
76815f0b8c3SMartin Matuska        int(arc_stats['prescient_prefetch'])
76915f0b8c3SMartin Matuska    prt_2('ARC predictive prefetches:',
77015f0b8c3SMartin Matuska           f_perc(arc_stats['predictive_prefetch'], all_prefetches),
77115f0b8c3SMartin Matuska           f_hits(arc_stats['predictive_prefetch']))
77215f0b8c3SMartin Matuska    prt_i2('Demand hits after predictive:',
77315f0b8c3SMartin Matuska           f_perc(arc_stats['demand_hit_predictive_prefetch'],
77415f0b8c3SMartin Matuska                  arc_stats['predictive_prefetch']),
77515f0b8c3SMartin Matuska           f_hits(arc_stats['demand_hit_predictive_prefetch']))
77615f0b8c3SMartin Matuska    prt_i2('Demand I/O hits after predictive:',
77715f0b8c3SMartin Matuska           f_perc(arc_stats['demand_iohit_predictive_prefetch'],
77815f0b8c3SMartin Matuska                  arc_stats['predictive_prefetch']),
77915f0b8c3SMartin Matuska           f_hits(arc_stats['demand_iohit_predictive_prefetch']))
78015f0b8c3SMartin Matuska    never = int(arc_stats['predictive_prefetch']) -\
78115f0b8c3SMartin Matuska        int(arc_stats['demand_hit_predictive_prefetch']) -\
78215f0b8c3SMartin Matuska        int(arc_stats['demand_iohit_predictive_prefetch'])
78315f0b8c3SMartin Matuska    prt_i2('Never demanded after predictive:',
78415f0b8c3SMartin Matuska           f_perc(never, arc_stats['predictive_prefetch']),
78515f0b8c3SMartin Matuska           f_hits(never))
78615f0b8c3SMartin Matuska    print()
78715f0b8c3SMartin Matuska
78815f0b8c3SMartin Matuska    prt_2('ARC prescient prefetches:',
78915f0b8c3SMartin Matuska           f_perc(arc_stats['prescient_prefetch'], all_prefetches),
79015f0b8c3SMartin Matuska           f_hits(arc_stats['prescient_prefetch']))
79115f0b8c3SMartin Matuska    prt_i2('Demand hits after prescient:',
79215f0b8c3SMartin Matuska           f_perc(arc_stats['demand_hit_prescient_prefetch'],
79315f0b8c3SMartin Matuska                  arc_stats['prescient_prefetch']),
79415f0b8c3SMartin Matuska           f_hits(arc_stats['demand_hit_prescient_prefetch']))
79515f0b8c3SMartin Matuska    prt_i2('Demand I/O hits after prescient:',
79615f0b8c3SMartin Matuska           f_perc(arc_stats['demand_iohit_prescient_prefetch'],
79715f0b8c3SMartin Matuska                  arc_stats['prescient_prefetch']),
79815f0b8c3SMartin Matuska           f_hits(arc_stats['demand_iohit_prescient_prefetch']))
79915f0b8c3SMartin Matuska    never = int(arc_stats['prescient_prefetch'])-\
80015f0b8c3SMartin Matuska        int(arc_stats['demand_hit_prescient_prefetch'])-\
80115f0b8c3SMartin Matuska        int(arc_stats['demand_iohit_prescient_prefetch'])
80215f0b8c3SMartin Matuska    prt_i2('Never demanded after prescient:',
80315f0b8c3SMartin Matuska           f_perc(never, arc_stats['prescient_prefetch']),
80415f0b8c3SMartin Matuska           f_hits(never))
80515f0b8c3SMartin Matuska    print()
80615f0b8c3SMartin Matuska
80715f0b8c3SMartin Matuska    print('ARC states hits of all accesses:')
808716fd348SMartin Matuska    cl_todo = (('Most frequently used (MFU):', arc_stats['mfu_hits']),
809716fd348SMartin Matuska               ('Most recently used (MRU):', arc_stats['mru_hits']),
810716fd348SMartin Matuska               ('Most frequently used (MFU) ghost:',
811716fd348SMartin Matuska                arc_stats['mfu_ghost_hits']),
812716fd348SMartin Matuska               ('Most recently used (MRU) ghost:',
81315f0b8c3SMartin Matuska                arc_stats['mru_ghost_hits']),
81415f0b8c3SMartin Matuska               ('Uncached:', arc_stats['uncached_hits']))
815716fd348SMartin Matuska    for title, value in cl_todo:
81615f0b8c3SMartin Matuska        prt_i2(title, f_perc(value, all_accesses), f_hits(value))
817716fd348SMartin Matuska    print()
818716fd348SMartin Matuska
819716fd348SMartin Matuska
820716fd348SMartin Matuskadef section_dmu(kstats_dict):
821716fd348SMartin Matuska    """Collect information on the DMU"""
822716fd348SMartin Matuska
823716fd348SMartin Matuska    zfetch_stats = isolate_section('zfetchstats', kstats_dict)
824716fd348SMartin Matuska
8251719886fSMartin Matuska    zfetch_access_total = int(zfetch_stats['hits']) +\
8261719886fSMartin Matuska        int(zfetch_stats['future']) + int(zfetch_stats['stride']) +\
8271719886fSMartin Matuska        int(zfetch_stats['past']) + int(zfetch_stats['misses'])
828716fd348SMartin Matuska
82915f0b8c3SMartin Matuska    prt_1('DMU predictive prefetcher calls:', f_hits(zfetch_access_total))
83015f0b8c3SMartin Matuska    prt_i2('Stream hits:',
83115f0b8c3SMartin Matuska           f_perc(zfetch_stats['hits'], zfetch_access_total),
832716fd348SMartin Matuska           f_hits(zfetch_stats['hits']))
8331719886fSMartin Matuska    future = int(zfetch_stats['future']) + int(zfetch_stats['stride'])
8341719886fSMartin Matuska    prt_i2('Hits ahead of stream:', f_perc(future, zfetch_access_total),
8351719886fSMartin Matuska           f_hits(future))
8361719886fSMartin Matuska    prt_i2('Hits behind stream:',
8371719886fSMartin Matuska           f_perc(zfetch_stats['past'], zfetch_access_total),
8381719886fSMartin Matuska           f_hits(zfetch_stats['past']))
83915f0b8c3SMartin Matuska    prt_i2('Stream misses:',
84015f0b8c3SMartin Matuska           f_perc(zfetch_stats['misses'], zfetch_access_total),
841716fd348SMartin Matuska           f_hits(zfetch_stats['misses']))
84215f0b8c3SMartin Matuska    prt_i2('Streams limit reached:',
84315f0b8c3SMartin Matuska           f_perc(zfetch_stats['max_streams'], zfetch_stats['misses']),
84415f0b8c3SMartin Matuska           f_hits(zfetch_stats['max_streams']))
8451719886fSMartin Matuska    prt_i1('Stream strides:', f_hits(zfetch_stats['stride']))
84615f0b8c3SMartin Matuska    prt_i1('Prefetches issued', f_hits(zfetch_stats['io_issued']))
847716fd348SMartin Matuska    print()
848716fd348SMartin Matuska
849716fd348SMartin Matuska
850716fd348SMartin Matuskadef section_l2arc(kstats_dict):
851716fd348SMartin Matuska    """Collect information on L2ARC device if present. If not, tell user
852716fd348SMartin Matuska    that we're skipping the section.
853716fd348SMartin Matuska    """
854716fd348SMartin Matuska
855716fd348SMartin Matuska    # The L2ARC statistics live in the same section as the normal ARC stuff
856716fd348SMartin Matuska    arc_stats = isolate_section('arcstats', kstats_dict)
857716fd348SMartin Matuska
858716fd348SMartin Matuska    if arc_stats['l2_size'] == '0':
859716fd348SMartin Matuska        print('L2ARC not detected, skipping section\n')
860716fd348SMartin Matuska        return
861716fd348SMartin Matuska
862716fd348SMartin Matuska    l2_errors = int(arc_stats['l2_writes_error']) +\
863716fd348SMartin Matuska        int(arc_stats['l2_cksum_bad']) +\
864716fd348SMartin Matuska        int(arc_stats['l2_io_error'])
865716fd348SMartin Matuska
866716fd348SMartin Matuska    l2_access_total = int(arc_stats['l2_hits'])+int(arc_stats['l2_misses'])
867716fd348SMartin Matuska    health = 'HEALTHY'
868716fd348SMartin Matuska
869716fd348SMartin Matuska    if l2_errors > 0:
870716fd348SMartin Matuska        health = 'DEGRADED'
871716fd348SMartin Matuska
872716fd348SMartin Matuska    prt_1('L2ARC status:', health)
873716fd348SMartin Matuska
874716fd348SMartin Matuska    l2_todo = (('Low memory aborts:', 'l2_abort_lowmem'),
875716fd348SMartin Matuska               ('Free on write:', 'l2_free_on_write'),
876716fd348SMartin Matuska               ('R/W clashes:', 'l2_rw_clash'),
877716fd348SMartin Matuska               ('Bad checksums:', 'l2_cksum_bad'),
8784e8d558cSMartin Matuska               ('Read errors:', 'l2_io_error'),
8794e8d558cSMartin Matuska               ('Write errors:', 'l2_writes_error'))
880716fd348SMartin Matuska
881716fd348SMartin Matuska    for title, value in l2_todo:
882716fd348SMartin Matuska        prt_i1(title, f_hits(arc_stats[value]))
883716fd348SMartin Matuska
884716fd348SMartin Matuska    print()
885716fd348SMartin Matuska    prt_1('L2ARC size (adaptive):', f_bytes(arc_stats['l2_size']))
886716fd348SMartin Matuska    prt_i2('Compressed:', f_perc(arc_stats['l2_asize'], arc_stats['l2_size']),
887716fd348SMartin Matuska           f_bytes(arc_stats['l2_asize']))
888716fd348SMartin Matuska    prt_i2('Header size:',
889716fd348SMartin Matuska           f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']),
890716fd348SMartin Matuska           f_bytes(arc_stats['l2_hdr_size']))
891716fd348SMartin Matuska    prt_i2('MFU allocated size:',
892716fd348SMartin Matuska           f_perc(arc_stats['l2_mfu_asize'], arc_stats['l2_asize']),
893716fd348SMartin Matuska           f_bytes(arc_stats['l2_mfu_asize']))
894716fd348SMartin Matuska    prt_i2('MRU allocated size:',
895716fd348SMartin Matuska           f_perc(arc_stats['l2_mru_asize'], arc_stats['l2_asize']),
896716fd348SMartin Matuska           f_bytes(arc_stats['l2_mru_asize']))
897716fd348SMartin Matuska    prt_i2('Prefetch allocated size:',
898716fd348SMartin Matuska           f_perc(arc_stats['l2_prefetch_asize'], arc_stats['l2_asize']),
899716fd348SMartin Matuska           f_bytes(arc_stats['l2_prefetch_asize']))
900716fd348SMartin Matuska    prt_i2('Data (buffer content) allocated size:',
901716fd348SMartin Matuska           f_perc(arc_stats['l2_bufc_data_asize'], arc_stats['l2_asize']),
902716fd348SMartin Matuska           f_bytes(arc_stats['l2_bufc_data_asize']))
903716fd348SMartin Matuska    prt_i2('Metadata (buffer content) allocated size:',
904716fd348SMartin Matuska           f_perc(arc_stats['l2_bufc_metadata_asize'], arc_stats['l2_asize']),
905716fd348SMartin Matuska           f_bytes(arc_stats['l2_bufc_metadata_asize']))
906716fd348SMartin Matuska
907716fd348SMartin Matuska    print()
908716fd348SMartin Matuska    prt_1('L2ARC breakdown:', f_hits(l2_access_total))
909716fd348SMartin Matuska    prt_i2('Hit ratio:',
910716fd348SMartin Matuska           f_perc(arc_stats['l2_hits'], l2_access_total),
911716fd348SMartin Matuska           f_hits(arc_stats['l2_hits']))
912716fd348SMartin Matuska    prt_i2('Miss ratio:',
913716fd348SMartin Matuska           f_perc(arc_stats['l2_misses'], l2_access_total),
914716fd348SMartin Matuska           f_hits(arc_stats['l2_misses']))
915716fd348SMartin Matuska
916716fd348SMartin Matuska    print()
9174e8d558cSMartin Matuska    print('L2ARC I/O:')
9184e8d558cSMartin Matuska    prt_i2('Reads:',
9194e8d558cSMartin Matuska           f_bytes(arc_stats['l2_read_bytes']),
9204e8d558cSMartin Matuska           f_hits(arc_stats['l2_hits']))
9214e8d558cSMartin Matuska    prt_i2('Writes:',
9224e8d558cSMartin Matuska           f_bytes(arc_stats['l2_write_bytes']),
9234e8d558cSMartin Matuska           f_hits(arc_stats['l2_writes_sent']))
924716fd348SMartin Matuska
925716fd348SMartin Matuska    print()
926716fd348SMartin Matuska    print('L2ARC evicts:')
9274e8d558cSMartin Matuska    prt_i1('L1 cached:', f_hits(arc_stats['l2_evict_l1cached']))
9284e8d558cSMartin Matuska    prt_i1('While reading:', f_hits(arc_stats['l2_evict_reading']))
929716fd348SMartin Matuska    print()
930716fd348SMartin Matuska
931716fd348SMartin Matuska
932716fd348SMartin Matuskadef section_spl(*_):
933716fd348SMartin Matuska    """Print the SPL parameters, if requested with alternative format
934716fd348SMartin Matuska    and/or descriptions. This does not use kstats.
935716fd348SMartin Matuska    """
936716fd348SMartin Matuska
937716fd348SMartin Matuska    if sys.platform.startswith('freebsd'):
938716fd348SMartin Matuska        # No SPL support in FreeBSD
939716fd348SMartin Matuska        return
940716fd348SMartin Matuska
941716fd348SMartin Matuska    spls = get_spl_params()
942716fd348SMartin Matuska    keylist = sorted(spls.keys())
943716fd348SMartin Matuska    print('Solaris Porting Layer (SPL):')
944716fd348SMartin Matuska
945716fd348SMartin Matuska    if ARGS.desc:
946716fd348SMartin Matuska        descriptions = get_descriptions('spl')
947716fd348SMartin Matuska
948716fd348SMartin Matuska    for key in keylist:
949716fd348SMartin Matuska        value = spls[key]
950716fd348SMartin Matuska
951716fd348SMartin Matuska        if ARGS.desc:
952716fd348SMartin Matuska            try:
953716fd348SMartin Matuska                print(INDENT+'#', descriptions[key])
954716fd348SMartin Matuska            except KeyError:
955716fd348SMartin Matuska                print(INDENT+'# (No description found)')  # paranoid
956716fd348SMartin Matuska
957716fd348SMartin Matuska        print(format_raw_line(key, value))
958716fd348SMartin Matuska
959716fd348SMartin Matuska    print()
960716fd348SMartin Matuska
961716fd348SMartin Matuska
962716fd348SMartin Matuskadef section_tunables(*_):
963716fd348SMartin Matuska    """Print the tunables, if requested with alternative format and/or
964716fd348SMartin Matuska    descriptions. This does not use kstasts.
965716fd348SMartin Matuska    """
966716fd348SMartin Matuska
967716fd348SMartin Matuska    tunables = get_tunable_params()
968716fd348SMartin Matuska    keylist = sorted(tunables.keys())
969716fd348SMartin Matuska    print('Tunables:')
970716fd348SMartin Matuska
971716fd348SMartin Matuska    if ARGS.desc:
972716fd348SMartin Matuska        descriptions = get_descriptions('zfs')
973716fd348SMartin Matuska
974716fd348SMartin Matuska    for key in keylist:
975716fd348SMartin Matuska        value = tunables[key]
976716fd348SMartin Matuska
977716fd348SMartin Matuska        if ARGS.desc:
978716fd348SMartin Matuska            try:
979716fd348SMartin Matuska                print(INDENT+'#', descriptions[key])
980716fd348SMartin Matuska            except KeyError:
981716fd348SMartin Matuska                print(INDENT+'# (No description found)')  # paranoid
982716fd348SMartin Matuska
983716fd348SMartin Matuska        print(format_raw_line(key, value))
984716fd348SMartin Matuska
985716fd348SMartin Matuska    print()
986716fd348SMartin Matuska
987716fd348SMartin Matuska
988716fd348SMartin Matuskadef section_zil(kstats_dict):
989716fd348SMartin Matuska    """Collect information on the ZFS Intent Log. Some of the information
990716fd348SMartin Matuska    taken from https://github.com/openzfs/zfs/blob/master/include/sys/zil.h
991716fd348SMartin Matuska    """
992716fd348SMartin Matuska
993716fd348SMartin Matuska    zil_stats = isolate_section('zil', kstats_dict)
994716fd348SMartin Matuska
995716fd348SMartin Matuska    prt_1('ZIL committed transactions:',
996716fd348SMartin Matuska          f_hits(zil_stats['zil_itx_count']))
997716fd348SMartin Matuska    prt_i1('Commit requests:', f_hits(zil_stats['zil_commit_count']))
998716fd348SMartin Matuska    prt_i1('Flushes to stable storage:',
999716fd348SMartin Matuska           f_hits(zil_stats['zil_commit_writer_count']))
1000716fd348SMartin Matuska    prt_i2('Transactions to SLOG storage pool:',
1001716fd348SMartin Matuska           f_bytes(zil_stats['zil_itx_metaslab_slog_bytes']),
1002716fd348SMartin Matuska           f_hits(zil_stats['zil_itx_metaslab_slog_count']))
1003716fd348SMartin Matuska    prt_i2('Transactions to non-SLOG storage pool:',
1004716fd348SMartin Matuska           f_bytes(zil_stats['zil_itx_metaslab_normal_bytes']),
1005716fd348SMartin Matuska           f_hits(zil_stats['zil_itx_metaslab_normal_count']))
1006716fd348SMartin Matuska    print()
1007716fd348SMartin Matuska
1008716fd348SMartin Matuska
1009716fd348SMartin Matuskasection_calls = {'arc': section_arc,
1010716fd348SMartin Matuska                 'archits': section_archits,
1011716fd348SMartin Matuska                 'dmu': section_dmu,
1012716fd348SMartin Matuska                 'l2arc': section_l2arc,
1013716fd348SMartin Matuska                 'spl': section_spl,
1014716fd348SMartin Matuska                 'tunables': section_tunables,
1015716fd348SMartin Matuska                 'zil': section_zil}
1016716fd348SMartin Matuska
1017716fd348SMartin Matuska
1018716fd348SMartin Matuskadef main():
1019716fd348SMartin Matuska    """Run program. The options to draw a graph and to print all data raw are
1020716fd348SMartin Matuska    treated separately because they come with their own call.
1021716fd348SMartin Matuska    """
1022716fd348SMartin Matuska
1023716fd348SMartin Matuska    kstats = get_kstats()
1024716fd348SMartin Matuska
1025716fd348SMartin Matuska    if ARGS.graph:
1026716fd348SMartin Matuska        draw_graph(kstats)
1027716fd348SMartin Matuska        sys.exit(0)
1028716fd348SMartin Matuska
1029716fd348SMartin Matuska    print_header()
1030716fd348SMartin Matuska
1031716fd348SMartin Matuska    if ARGS.raw:
1032716fd348SMartin Matuska        print_raw(kstats)
1033716fd348SMartin Matuska
1034716fd348SMartin Matuska    elif ARGS.section:
1035716fd348SMartin Matuska
1036716fd348SMartin Matuska        try:
1037716fd348SMartin Matuska            section_calls[ARGS.section](kstats)
1038716fd348SMartin Matuska        except KeyError:
1039716fd348SMartin Matuska            print('Error: Section "{0}" unknown'.format(ARGS.section))
1040716fd348SMartin Matuska            sys.exit(1)
1041716fd348SMartin Matuska
1042716fd348SMartin Matuska    elif ARGS.page:
1043716fd348SMartin Matuska        print('WARNING: Pages are deprecated, please use "--section"\n')
1044716fd348SMartin Matuska
1045716fd348SMartin Matuska        pages_to_calls = {1: 'arc',
1046716fd348SMartin Matuska                          2: 'archits',
1047716fd348SMartin Matuska                          3: 'l2arc',
1048716fd348SMartin Matuska                          4: 'dmu',
1049716fd348SMartin Matuska                          5: 'vdev',
1050716fd348SMartin Matuska                          6: 'tunables'}
1051716fd348SMartin Matuska
1052716fd348SMartin Matuska        try:
1053716fd348SMartin Matuska            call = pages_to_calls[ARGS.page]
1054716fd348SMartin Matuska        except KeyError:
1055716fd348SMartin Matuska            print('Error: Page "{0}" not supported'.format(ARGS.page))
1056716fd348SMartin Matuska            sys.exit(1)
1057716fd348SMartin Matuska        else:
1058716fd348SMartin Matuska            section_calls[call](kstats)
1059716fd348SMartin Matuska
1060716fd348SMartin Matuska    else:
1061716fd348SMartin Matuska        # If no parameters were given, we print all sections. We might want to
1062716fd348SMartin Matuska        # change the sequence by hand
1063716fd348SMartin Matuska        calls = sorted(section_calls.keys())
1064716fd348SMartin Matuska
1065716fd348SMartin Matuska        for section in calls:
1066716fd348SMartin Matuska            section_calls[section](kstats)
1067716fd348SMartin Matuska
1068716fd348SMartin Matuska    sys.exit(0)
1069716fd348SMartin Matuska
1070716fd348SMartin Matuska
1071716fd348SMartin Matuskaif __name__ == '__main__':
1072716fd348SMartin Matuska    main()
1073