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