xref: /freebsd/sys/contrib/openzfs/cmd/arcstat.in (revision 716fd348e01c5f2ba125f878a634a753436c2994)
1*716fd348SMartin Matuska#!/usr/bin/env @PYTHON_SHEBANG@
2*716fd348SMartin Matuska#
3*716fd348SMartin Matuska# Print out ZFS ARC Statistics exported via kstat(1)
4*716fd348SMartin Matuska# For a definition of fields, or usage, use arcstat -v
5*716fd348SMartin Matuska#
6*716fd348SMartin Matuska# This script was originally a fork of the original arcstat.pl (0.1)
7*716fd348SMartin Matuska# by Neelakanth Nadgir, originally published on his Sun blog on
8*716fd348SMartin Matuska# 09/18/2007
9*716fd348SMartin Matuska#     http://blogs.sun.com/realneel/entry/zfs_arc_statistics
10*716fd348SMartin Matuska#
11*716fd348SMartin Matuska# A new version aimed to improve upon the original by adding features
12*716fd348SMartin Matuska# and fixing bugs as needed.  This version was maintained by Mike
13*716fd348SMartin Matuska# Harsch and was hosted in a public open source repository:
14*716fd348SMartin Matuska#    http://github.com/mharsch/arcstat
15*716fd348SMartin Matuska#
16*716fd348SMartin Matuska# but has since moved to the illumos-gate repository.
17*716fd348SMartin Matuska#
18*716fd348SMartin Matuska# This Python port was written by John Hixson for FreeNAS, introduced
19*716fd348SMartin Matuska# in commit e2c29f:
20*716fd348SMartin Matuska#    https://github.com/freenas/freenas
21*716fd348SMartin Matuska#
22*716fd348SMartin Matuska# and has been improved by many people since.
23*716fd348SMartin Matuska#
24*716fd348SMartin Matuska# CDDL HEADER START
25*716fd348SMartin Matuska#
26*716fd348SMartin Matuska# The contents of this file are subject to the terms of the
27*716fd348SMartin Matuska# Common Development and Distribution License, Version 1.0 only
28*716fd348SMartin Matuska# (the "License").  You may not use this file except in compliance
29*716fd348SMartin Matuska# with the License.
30*716fd348SMartin Matuska#
31*716fd348SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
32*716fd348SMartin Matuska# or http://www.opensolaris.org/os/licensing.
33*716fd348SMartin Matuska# See the License for the specific language governing permissions
34*716fd348SMartin Matuska# and limitations under the License.
35*716fd348SMartin Matuska#
36*716fd348SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
37*716fd348SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
38*716fd348SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
39*716fd348SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
40*716fd348SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
41*716fd348SMartin Matuska#
42*716fd348SMartin Matuska# CDDL HEADER END
43*716fd348SMartin Matuska#
44*716fd348SMartin Matuska#
45*716fd348SMartin Matuska# Fields have a fixed width. Every interval, we fill the "v"
46*716fd348SMartin Matuska# hash with its corresponding value (v[field]=value) using calculate().
47*716fd348SMartin Matuska# @hdr is the array of fields that needs to be printed, so we
48*716fd348SMartin Matuska# just iterate over this array and print the values using our pretty printer.
49*716fd348SMartin Matuska#
50*716fd348SMartin Matuska# This script must remain compatible with Python 3.6+.
51*716fd348SMartin Matuska#
52*716fd348SMartin Matuska
53*716fd348SMartin Matuskaimport sys
54*716fd348SMartin Matuskaimport time
55*716fd348SMartin Matuskaimport getopt
56*716fd348SMartin Matuskaimport re
57*716fd348SMartin Matuskaimport copy
58*716fd348SMartin Matuska
59*716fd348SMartin Matuskafrom signal import signal, SIGINT, SIGWINCH, SIG_DFL
60*716fd348SMartin Matuska
61*716fd348SMartin Matuska
62*716fd348SMartin Matuskacols = {
63*716fd348SMartin Matuska    # HDR:        [Size, Scale, Description]
64*716fd348SMartin Matuska    "time":       [8, -1, "Time"],
65*716fd348SMartin Matuska    "hits":       [4, 1000, "ARC reads per second"],
66*716fd348SMartin Matuska    "miss":       [4, 1000, "ARC misses per second"],
67*716fd348SMartin Matuska    "read":       [4, 1000, "Total ARC accesses per second"],
68*716fd348SMartin Matuska    "hit%":       [4, 100, "ARC hit percentage"],
69*716fd348SMartin Matuska    "miss%":      [5, 100, "ARC miss percentage"],
70*716fd348SMartin Matuska    "dhit":       [4, 1000, "Demand hits per second"],
71*716fd348SMartin Matuska    "dmis":       [4, 1000, "Demand misses per second"],
72*716fd348SMartin Matuska    "dh%":        [3, 100, "Demand hit percentage"],
73*716fd348SMartin Matuska    "dm%":        [3, 100, "Demand miss percentage"],
74*716fd348SMartin Matuska    "phit":       [4, 1000, "Prefetch hits per second"],
75*716fd348SMartin Matuska    "pmis":       [4, 1000, "Prefetch misses per second"],
76*716fd348SMartin Matuska    "ph%":        [3, 100, "Prefetch hits percentage"],
77*716fd348SMartin Matuska    "pm%":        [3, 100, "Prefetch miss percentage"],
78*716fd348SMartin Matuska    "mhit":       [4, 1000, "Metadata hits per second"],
79*716fd348SMartin Matuska    "mmis":       [4, 1000, "Metadata misses per second"],
80*716fd348SMartin Matuska    "mread":      [5, 1000, "Metadata accesses per second"],
81*716fd348SMartin Matuska    "mh%":        [3, 100, "Metadata hit percentage"],
82*716fd348SMartin Matuska    "mm%":        [3, 100, "Metadata miss percentage"],
83*716fd348SMartin Matuska    "arcsz":      [5, 1024, "ARC size"],
84*716fd348SMartin Matuska    "size":       [4, 1024, "ARC size"],
85*716fd348SMartin Matuska    "c":          [4, 1024, "ARC target size"],
86*716fd348SMartin Matuska    "mfu":        [4, 1000, "MFU list hits per second"],
87*716fd348SMartin Matuska    "mru":        [4, 1000, "MRU list hits per second"],
88*716fd348SMartin Matuska    "mfug":       [4, 1000, "MFU ghost list hits per second"],
89*716fd348SMartin Matuska    "mrug":       [4, 1000, "MRU ghost list hits per second"],
90*716fd348SMartin Matuska    "eskip":      [5, 1000, "evict_skip per second"],
91*716fd348SMartin Matuska    "el2skip":    [7, 1000, "evict skip, due to l2 writes, per second"],
92*716fd348SMartin Matuska    "el2cach":    [7, 1024, "Size of L2 cached evictions per second"],
93*716fd348SMartin Matuska    "el2el":      [5, 1024, "Size of L2 eligible evictions per second"],
94*716fd348SMartin Matuska    "el2mfu":     [6, 1024, "Size of L2 eligible MFU evictions per second"],
95*716fd348SMartin Matuska    "el2mru":     [6, 1024, "Size of L2 eligible MRU evictions per second"],
96*716fd348SMartin Matuska    "el2inel":    [7, 1024, "Size of L2 ineligible evictions per second"],
97*716fd348SMartin Matuska    "mtxmis":     [6, 1000, "mutex_miss per second"],
98*716fd348SMartin Matuska    "dread":      [5, 1000, "Demand accesses per second"],
99*716fd348SMartin Matuska    "pread":      [5, 1000, "Prefetch accesses per second"],
100*716fd348SMartin Matuska    "l2hits":     [6, 1000, "L2ARC hits per second"],
101*716fd348SMartin Matuska    "l2miss":     [6, 1000, "L2ARC misses per second"],
102*716fd348SMartin Matuska    "l2read":     [6, 1000, "Total L2ARC accesses per second"],
103*716fd348SMartin Matuska    "l2hit%":     [6, 100, "L2ARC access hit percentage"],
104*716fd348SMartin Matuska    "l2miss%":    [7, 100, "L2ARC access miss percentage"],
105*716fd348SMartin Matuska    "l2pref":     [6, 1024, "L2ARC prefetch allocated size"],
106*716fd348SMartin Matuska    "l2mfu":      [5, 1024, "L2ARC MFU allocated size"],
107*716fd348SMartin Matuska    "l2mru":      [5, 1024, "L2ARC MRU allocated size"],
108*716fd348SMartin Matuska    "l2data":     [6, 1024, "L2ARC data allocated size"],
109*716fd348SMartin Matuska    "l2meta":     [6, 1024, "L2ARC metadata allocated size"],
110*716fd348SMartin Matuska    "l2pref%":    [7, 100, "L2ARC prefetch percentage"],
111*716fd348SMartin Matuska    "l2mfu%":     [6, 100, "L2ARC MFU percentage"],
112*716fd348SMartin Matuska    "l2mru%":     [6, 100, "L2ARC MRU percentage"],
113*716fd348SMartin Matuska    "l2data%":    [7, 100, "L2ARC data percentage"],
114*716fd348SMartin Matuska    "l2meta%":    [7, 100, "L2ARC metadata percentage"],
115*716fd348SMartin Matuska    "l2asize":    [7, 1024, "Actual (compressed) size of the L2ARC"],
116*716fd348SMartin Matuska    "l2size":     [6, 1024, "Size of the L2ARC"],
117*716fd348SMartin Matuska    "l2bytes":    [7, 1024, "Bytes read per second from the L2ARC"],
118*716fd348SMartin Matuska    "grow":       [4, 1000, "ARC grow disabled"],
119*716fd348SMartin Matuska    "need":       [4, 1024, "ARC reclaim need"],
120*716fd348SMartin Matuska    "free":       [4, 1024, "ARC free memory"],
121*716fd348SMartin Matuska    "avail":      [5, 1024, "ARC available memory"],
122*716fd348SMartin Matuska    "waste":      [5, 1024, "Wasted memory due to round up to pagesize"],
123*716fd348SMartin Matuska}
124*716fd348SMartin Matuska
125*716fd348SMartin Matuskav = {}
126*716fd348SMartin Matuskahdr = ["time", "read", "miss", "miss%", "dmis", "dm%", "pmis", "pm%", "mmis",
127*716fd348SMartin Matuska       "mm%", "size", "c", "avail"]
128*716fd348SMartin Matuskaxhdr = ["time", "mfu", "mru", "mfug", "mrug", "eskip", "mtxmis", "dread",
129*716fd348SMartin Matuska        "pread", "read"]
130*716fd348SMartin Matuskasint = 1               # Default interval is 1 second
131*716fd348SMartin Matuskacount = 1              # Default count is 1
132*716fd348SMartin Matuskahdr_intr = 20          # Print header every 20 lines of output
133*716fd348SMartin Matuskaopfile = None
134*716fd348SMartin Matuskasep = "  "              # Default separator is 2 spaces
135*716fd348SMartin Matuskaversion = "0.4"
136*716fd348SMartin Matuskal2exist = False
137*716fd348SMartin Matuskacmd = ("Usage: arcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
138*716fd348SMartin Matuska       "[count]]\n")
139*716fd348SMartin Matuskacur = {}
140*716fd348SMartin Matuskad = {}
141*716fd348SMartin Matuskaout = None
142*716fd348SMartin Matuskakstat = None
143*716fd348SMartin Matuskapretty_print = True
144*716fd348SMartin Matuska
145*716fd348SMartin Matuska
146*716fd348SMartin Matuskaif sys.platform.startswith('freebsd'):
147*716fd348SMartin Matuska    # Requires py-sysctl on FreeBSD
148*716fd348SMartin Matuska    import sysctl
149*716fd348SMartin Matuska
150*716fd348SMartin Matuska    def kstat_update():
151*716fd348SMartin Matuska        global kstat
152*716fd348SMartin Matuska
153*716fd348SMartin Matuska        k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats')
154*716fd348SMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
155*716fd348SMartin Matuska
156*716fd348SMartin Matuska        if not k:
157*716fd348SMartin Matuska            sys.exit(1)
158*716fd348SMartin Matuska
159*716fd348SMartin Matuska        kstat = {}
160*716fd348SMartin Matuska
161*716fd348SMartin Matuska        for s in k:
162*716fd348SMartin Matuska            if not s:
163*716fd348SMartin Matuska                continue
164*716fd348SMartin Matuska
165*716fd348SMartin Matuska            name, value = s.name, s.value
166*716fd348SMartin Matuska            # Trims 'kstat.zfs.misc.arcstats' from the name
167*716fd348SMartin Matuska            kstat[name[24:]] = int(value)
168*716fd348SMartin Matuska
169*716fd348SMartin Matuskaelif sys.platform.startswith('linux'):
170*716fd348SMartin Matuska    def kstat_update():
171*716fd348SMartin Matuska        global kstat
172*716fd348SMartin Matuska
173*716fd348SMartin Matuska        k = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
174*716fd348SMartin Matuska
175*716fd348SMartin Matuska        if not k:
176*716fd348SMartin Matuska            sys.exit(1)
177*716fd348SMartin Matuska
178*716fd348SMartin Matuska        del k[0:2]
179*716fd348SMartin Matuska        kstat = {}
180*716fd348SMartin Matuska
181*716fd348SMartin Matuska        for s in k:
182*716fd348SMartin Matuska            if not s:
183*716fd348SMartin Matuska                continue
184*716fd348SMartin Matuska
185*716fd348SMartin Matuska            name, unused, value = s.split()
186*716fd348SMartin Matuska            kstat[name] = int(value)
187*716fd348SMartin Matuska
188*716fd348SMartin Matuska
189*716fd348SMartin Matuskadef detailed_usage():
190*716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
191*716fd348SMartin Matuska    sys.stderr.write("Field definitions are as follows:\n")
192*716fd348SMartin Matuska    for key in cols:
193*716fd348SMartin Matuska        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
194*716fd348SMartin Matuska    sys.stderr.write("\n")
195*716fd348SMartin Matuska
196*716fd348SMartin Matuska    sys.exit(0)
197*716fd348SMartin Matuska
198*716fd348SMartin Matuska
199*716fd348SMartin Matuskadef usage():
200*716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
201*716fd348SMartin Matuska    sys.stderr.write("\t -h : Print this help message\n")
202*716fd348SMartin Matuska    sys.stderr.write("\t -a : Print all possible stats\n")
203*716fd348SMartin Matuska    sys.stderr.write("\t -v : List all possible field headers and definitions"
204*716fd348SMartin Matuska                     "\n")
205*716fd348SMartin Matuska    sys.stderr.write("\t -x : Print extended stats\n")
206*716fd348SMartin Matuska    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
207*716fd348SMartin Matuska    sys.stderr.write("\t -o : Redirect output to the specified file\n")
208*716fd348SMartin Matuska    sys.stderr.write("\t -s : Override default field separator with custom "
209*716fd348SMartin Matuska                     "character or string\n")
210*716fd348SMartin Matuska    sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n")
211*716fd348SMartin Matuska    sys.stderr.write("\nExamples:\n")
212*716fd348SMartin Matuska    sys.stderr.write("\tarcstat -o /tmp/a.log 2 10\n")
213*716fd348SMartin Matuska    sys.stderr.write("\tarcstat -s \",\" -o /tmp/a.log 2 10\n")
214*716fd348SMartin Matuska    sys.stderr.write("\tarcstat -v\n")
215*716fd348SMartin Matuska    sys.stderr.write("\tarcstat -f time,hit%,dh%,ph%,mh% 1\n")
216*716fd348SMartin Matuska    sys.stderr.write("\n")
217*716fd348SMartin Matuska
218*716fd348SMartin Matuska    sys.exit(1)
219*716fd348SMartin Matuska
220*716fd348SMartin Matuska
221*716fd348SMartin Matuskadef snap_stats():
222*716fd348SMartin Matuska    global cur
223*716fd348SMartin Matuska    global kstat
224*716fd348SMartin Matuska
225*716fd348SMartin Matuska    prev = copy.deepcopy(cur)
226*716fd348SMartin Matuska    kstat_update()
227*716fd348SMartin Matuska
228*716fd348SMartin Matuska    cur = kstat
229*716fd348SMartin Matuska    for key in cur:
230*716fd348SMartin Matuska        if re.match(key, "class"):
231*716fd348SMartin Matuska            continue
232*716fd348SMartin Matuska        if key in prev:
233*716fd348SMartin Matuska            d[key] = cur[key] - prev[key]
234*716fd348SMartin Matuska        else:
235*716fd348SMartin Matuska            d[key] = cur[key]
236*716fd348SMartin Matuska
237*716fd348SMartin Matuska
238*716fd348SMartin Matuskadef prettynum(sz, scale, num=0):
239*716fd348SMartin Matuska    suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
240*716fd348SMartin Matuska    index = 0
241*716fd348SMartin Matuska    save = 0
242*716fd348SMartin Matuska
243*716fd348SMartin Matuska    # Special case for date field
244*716fd348SMartin Matuska    if scale == -1:
245*716fd348SMartin Matuska        return "%s" % num
246*716fd348SMartin Matuska
247*716fd348SMartin Matuska    # Rounding error, return 0
248*716fd348SMartin Matuska    elif 0 < num < 1:
249*716fd348SMartin Matuska        num = 0
250*716fd348SMartin Matuska
251*716fd348SMartin Matuska    while abs(num) > scale and index < 5:
252*716fd348SMartin Matuska        save = num
253*716fd348SMartin Matuska        num = num / scale
254*716fd348SMartin Matuska        index += 1
255*716fd348SMartin Matuska
256*716fd348SMartin Matuska    if index == 0:
257*716fd348SMartin Matuska        return "%*d" % (sz, num)
258*716fd348SMartin Matuska
259*716fd348SMartin Matuska    if abs(save / scale) < 10:
260*716fd348SMartin Matuska        return "%*.1f%s" % (sz - 1, num, suffix[index])
261*716fd348SMartin Matuska    else:
262*716fd348SMartin Matuska        return "%*d%s" % (sz - 1, num, suffix[index])
263*716fd348SMartin Matuska
264*716fd348SMartin Matuska
265*716fd348SMartin Matuskadef print_values():
266*716fd348SMartin Matuska    global hdr
267*716fd348SMartin Matuska    global sep
268*716fd348SMartin Matuska    global v
269*716fd348SMartin Matuska    global pretty_print
270*716fd348SMartin Matuska
271*716fd348SMartin Matuska    if pretty_print:
272*716fd348SMartin Matuska        fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
273*716fd348SMartin Matuska    else:
274*716fd348SMartin Matuska        fmt = lambda col: v[col]
275*716fd348SMartin Matuska
276*716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
277*716fd348SMartin Matuska    sys.stdout.write("\n")
278*716fd348SMartin Matuska    sys.stdout.flush()
279*716fd348SMartin Matuska
280*716fd348SMartin Matuska
281*716fd348SMartin Matuskadef print_header():
282*716fd348SMartin Matuska    global hdr
283*716fd348SMartin Matuska    global sep
284*716fd348SMartin Matuska    global pretty_print
285*716fd348SMartin Matuska
286*716fd348SMartin Matuska    if pretty_print:
287*716fd348SMartin Matuska        fmt = lambda col: "%*s" % (cols[col][0], col)
288*716fd348SMartin Matuska    else:
289*716fd348SMartin Matuska        fmt = lambda col: col
290*716fd348SMartin Matuska
291*716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
292*716fd348SMartin Matuska    sys.stdout.write("\n")
293*716fd348SMartin Matuska
294*716fd348SMartin Matuska
295*716fd348SMartin Matuskadef get_terminal_lines():
296*716fd348SMartin Matuska    try:
297*716fd348SMartin Matuska        import fcntl
298*716fd348SMartin Matuska        import termios
299*716fd348SMartin Matuska        import struct
300*716fd348SMartin Matuska        data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
301*716fd348SMartin Matuska        sz = struct.unpack('hh', data)
302*716fd348SMartin Matuska        return sz[0]
303*716fd348SMartin Matuska    except Exception:
304*716fd348SMartin Matuska        pass
305*716fd348SMartin Matuska
306*716fd348SMartin Matuska
307*716fd348SMartin Matuskadef update_hdr_intr():
308*716fd348SMartin Matuska    global hdr_intr
309*716fd348SMartin Matuska
310*716fd348SMartin Matuska    lines = get_terminal_lines()
311*716fd348SMartin Matuska    if lines and lines > 3:
312*716fd348SMartin Matuska        hdr_intr = lines - 3
313*716fd348SMartin Matuska
314*716fd348SMartin Matuska
315*716fd348SMartin Matuskadef resize_handler(signum, frame):
316*716fd348SMartin Matuska    update_hdr_intr()
317*716fd348SMartin Matuska
318*716fd348SMartin Matuska
319*716fd348SMartin Matuskadef init():
320*716fd348SMartin Matuska    global sint
321*716fd348SMartin Matuska    global count
322*716fd348SMartin Matuska    global hdr
323*716fd348SMartin Matuska    global xhdr
324*716fd348SMartin Matuska    global opfile
325*716fd348SMartin Matuska    global sep
326*716fd348SMartin Matuska    global out
327*716fd348SMartin Matuska    global l2exist
328*716fd348SMartin Matuska    global pretty_print
329*716fd348SMartin Matuska
330*716fd348SMartin Matuska    desired_cols = None
331*716fd348SMartin Matuska    aflag = False
332*716fd348SMartin Matuska    xflag = False
333*716fd348SMartin Matuska    hflag = False
334*716fd348SMartin Matuska    vflag = False
335*716fd348SMartin Matuska    i = 1
336*716fd348SMartin Matuska
337*716fd348SMartin Matuska    try:
338*716fd348SMartin Matuska        opts, args = getopt.getopt(
339*716fd348SMartin Matuska            sys.argv[1:],
340*716fd348SMartin Matuska            "axo:hvs:f:p",
341*716fd348SMartin Matuska            [
342*716fd348SMartin Matuska                "all",
343*716fd348SMartin Matuska                "extended",
344*716fd348SMartin Matuska                "outfile",
345*716fd348SMartin Matuska                "help",
346*716fd348SMartin Matuska                "verbose",
347*716fd348SMartin Matuska                "separator",
348*716fd348SMartin Matuska                "columns",
349*716fd348SMartin Matuska                "parsable"
350*716fd348SMartin Matuska            ]
351*716fd348SMartin Matuska        )
352*716fd348SMartin Matuska    except getopt.error as msg:
353*716fd348SMartin Matuska        sys.stderr.write("Error: %s\n" % str(msg))
354*716fd348SMartin Matuska        usage()
355*716fd348SMartin Matuska        opts = None
356*716fd348SMartin Matuska
357*716fd348SMartin Matuska    for opt, arg in opts:
358*716fd348SMartin Matuska        if opt in ('-a', '--all'):
359*716fd348SMartin Matuska            aflag = True
360*716fd348SMartin Matuska        if opt in ('-x', '--extended'):
361*716fd348SMartin Matuska            xflag = True
362*716fd348SMartin Matuska        if opt in ('-o', '--outfile'):
363*716fd348SMartin Matuska            opfile = arg
364*716fd348SMartin Matuska            i += 1
365*716fd348SMartin Matuska        if opt in ('-h', '--help'):
366*716fd348SMartin Matuska            hflag = True
367*716fd348SMartin Matuska        if opt in ('-v', '--verbose'):
368*716fd348SMartin Matuska            vflag = True
369*716fd348SMartin Matuska        if opt in ('-s', '--separator'):
370*716fd348SMartin Matuska            sep = arg
371*716fd348SMartin Matuska            i += 1
372*716fd348SMartin Matuska        if opt in ('-f', '--columns'):
373*716fd348SMartin Matuska            desired_cols = arg
374*716fd348SMartin Matuska            i += 1
375*716fd348SMartin Matuska        if opt in ('-p', '--parsable'):
376*716fd348SMartin Matuska            pretty_print = False
377*716fd348SMartin Matuska        i += 1
378*716fd348SMartin Matuska
379*716fd348SMartin Matuska    argv = sys.argv[i:]
380*716fd348SMartin Matuska    sint = int(argv[0]) if argv else sint
381*716fd348SMartin Matuska    count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1)
382*716fd348SMartin Matuska
383*716fd348SMartin Matuska    if hflag or (xflag and desired_cols):
384*716fd348SMartin Matuska        usage()
385*716fd348SMartin Matuska
386*716fd348SMartin Matuska    if vflag:
387*716fd348SMartin Matuska        detailed_usage()
388*716fd348SMartin Matuska
389*716fd348SMartin Matuska    if xflag:
390*716fd348SMartin Matuska        hdr = xhdr
391*716fd348SMartin Matuska
392*716fd348SMartin Matuska    update_hdr_intr()
393*716fd348SMartin Matuska
394*716fd348SMartin Matuska    # check if L2ARC exists
395*716fd348SMartin Matuska    snap_stats()
396*716fd348SMartin Matuska    l2_size = cur.get("l2_size")
397*716fd348SMartin Matuska    if l2_size:
398*716fd348SMartin Matuska        l2exist = True
399*716fd348SMartin Matuska
400*716fd348SMartin Matuska    if desired_cols:
401*716fd348SMartin Matuska        hdr = desired_cols.split(",")
402*716fd348SMartin Matuska
403*716fd348SMartin Matuska        invalid = []
404*716fd348SMartin Matuska        incompat = []
405*716fd348SMartin Matuska        for ele in hdr:
406*716fd348SMartin Matuska            if ele not in cols:
407*716fd348SMartin Matuska                invalid.append(ele)
408*716fd348SMartin Matuska            elif not l2exist and ele.startswith("l2"):
409*716fd348SMartin Matuska                sys.stdout.write("No L2ARC Here\n%s\n" % ele)
410*716fd348SMartin Matuska                incompat.append(ele)
411*716fd348SMartin Matuska
412*716fd348SMartin Matuska        if len(invalid) > 0:
413*716fd348SMartin Matuska            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
414*716fd348SMartin Matuska            usage()
415*716fd348SMartin Matuska
416*716fd348SMartin Matuska        if len(incompat) > 0:
417*716fd348SMartin Matuska            sys.stderr.write("Incompatible field specified! -- %s\n" %
418*716fd348SMartin Matuska                             incompat)
419*716fd348SMartin Matuska            usage()
420*716fd348SMartin Matuska
421*716fd348SMartin Matuska    if aflag:
422*716fd348SMartin Matuska        if l2exist:
423*716fd348SMartin Matuska            hdr = cols.keys()
424*716fd348SMartin Matuska        else:
425*716fd348SMartin Matuska            hdr = [col for col in cols.keys() if not col.startswith("l2")]
426*716fd348SMartin Matuska
427*716fd348SMartin Matuska    if opfile:
428*716fd348SMartin Matuska        try:
429*716fd348SMartin Matuska            out = open(opfile, "w")
430*716fd348SMartin Matuska            sys.stdout = out
431*716fd348SMartin Matuska
432*716fd348SMartin Matuska        except IOError:
433*716fd348SMartin Matuska            sys.stderr.write("Cannot open %s for writing\n" % opfile)
434*716fd348SMartin Matuska            sys.exit(1)
435*716fd348SMartin Matuska
436*716fd348SMartin Matuska
437*716fd348SMartin Matuskadef calculate():
438*716fd348SMartin Matuska    global d
439*716fd348SMartin Matuska    global v
440*716fd348SMartin Matuska    global l2exist
441*716fd348SMartin Matuska
442*716fd348SMartin Matuska    v = dict()
443*716fd348SMartin Matuska    v["time"] = time.strftime("%H:%M:%S", time.localtime())
444*716fd348SMartin Matuska    v["hits"] = d["hits"] // sint
445*716fd348SMartin Matuska    v["miss"] = d["misses"] // sint
446*716fd348SMartin Matuska    v["read"] = v["hits"] + v["miss"]
447*716fd348SMartin Matuska    v["hit%"] = 100 * v["hits"] // v["read"] if v["read"] > 0 else 0
448*716fd348SMartin Matuska    v["miss%"] = 100 - v["hit%"] if v["read"] > 0 else 0
449*716fd348SMartin Matuska
450*716fd348SMartin Matuska    v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) // sint
451*716fd348SMartin Matuska    v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) // sint
452*716fd348SMartin Matuska
453*716fd348SMartin Matuska    v["dread"] = v["dhit"] + v["dmis"]
454*716fd348SMartin Matuska    v["dh%"] = 100 * v["dhit"] // v["dread"] if v["dread"] > 0 else 0
455*716fd348SMartin Matuska    v["dm%"] = 100 - v["dh%"] if v["dread"] > 0 else 0
456*716fd348SMartin Matuska
457*716fd348SMartin Matuska    v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) // sint
458*716fd348SMartin Matuska    v["pmis"] = (d["prefetch_data_misses"] +
459*716fd348SMartin Matuska                 d["prefetch_metadata_misses"]) // sint
460*716fd348SMartin Matuska
461*716fd348SMartin Matuska    v["pread"] = v["phit"] + v["pmis"]
462*716fd348SMartin Matuska    v["ph%"] = 100 * v["phit"] // v["pread"] if v["pread"] > 0 else 0
463*716fd348SMartin Matuska    v["pm%"] = 100 - v["ph%"] if v["pread"] > 0 else 0
464*716fd348SMartin Matuska
465*716fd348SMartin Matuska    v["mhit"] = (d["prefetch_metadata_hits"] +
466*716fd348SMartin Matuska                 d["demand_metadata_hits"]) // sint
467*716fd348SMartin Matuska    v["mmis"] = (d["prefetch_metadata_misses"] +
468*716fd348SMartin Matuska                 d["demand_metadata_misses"]) // sint
469*716fd348SMartin Matuska
470*716fd348SMartin Matuska    v["mread"] = v["mhit"] + v["mmis"]
471*716fd348SMartin Matuska    v["mh%"] = 100 * v["mhit"] // v["mread"] if v["mread"] > 0 else 0
472*716fd348SMartin Matuska    v["mm%"] = 100 - v["mh%"] if v["mread"] > 0 else 0
473*716fd348SMartin Matuska
474*716fd348SMartin Matuska    v["arcsz"] = cur["size"]
475*716fd348SMartin Matuska    v["size"] = cur["size"]
476*716fd348SMartin Matuska    v["c"] = cur["c"]
477*716fd348SMartin Matuska    v["mfu"] = d["mfu_hits"] // sint
478*716fd348SMartin Matuska    v["mru"] = d["mru_hits"] // sint
479*716fd348SMartin Matuska    v["mrug"] = d["mru_ghost_hits"] // sint
480*716fd348SMartin Matuska    v["mfug"] = d["mfu_ghost_hits"] // sint
481*716fd348SMartin Matuska    v["eskip"] = d["evict_skip"] // sint
482*716fd348SMartin Matuska    v["el2skip"] = d["evict_l2_skip"] // sint
483*716fd348SMartin Matuska    v["el2cach"] = d["evict_l2_cached"] // sint
484*716fd348SMartin Matuska    v["el2el"] = d["evict_l2_eligible"] // sint
485*716fd348SMartin Matuska    v["el2mfu"] = d["evict_l2_eligible_mfu"] // sint
486*716fd348SMartin Matuska    v["el2mru"] = d["evict_l2_eligible_mru"] // sint
487*716fd348SMartin Matuska    v["el2inel"] = d["evict_l2_ineligible"] // sint
488*716fd348SMartin Matuska    v["mtxmis"] = d["mutex_miss"] // sint
489*716fd348SMartin Matuska
490*716fd348SMartin Matuska    if l2exist:
491*716fd348SMartin Matuska        v["l2hits"] = d["l2_hits"] // sint
492*716fd348SMartin Matuska        v["l2miss"] = d["l2_misses"] // sint
493*716fd348SMartin Matuska        v["l2read"] = v["l2hits"] + v["l2miss"]
494*716fd348SMartin Matuska        v["l2hit%"] = 100 * v["l2hits"] // v["l2read"] if v["l2read"] > 0 else 0
495*716fd348SMartin Matuska
496*716fd348SMartin Matuska        v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
497*716fd348SMartin Matuska        v["l2asize"] = cur["l2_asize"]
498*716fd348SMartin Matuska        v["l2size"] = cur["l2_size"]
499*716fd348SMartin Matuska        v["l2bytes"] = d["l2_read_bytes"] // sint
500*716fd348SMartin Matuska
501*716fd348SMartin Matuska        v["l2pref"] = cur["l2_prefetch_asize"]
502*716fd348SMartin Matuska        v["l2mfu"] = cur["l2_mfu_asize"]
503*716fd348SMartin Matuska        v["l2mru"] = cur["l2_mru_asize"]
504*716fd348SMartin Matuska        v["l2data"] = cur["l2_bufc_data_asize"]
505*716fd348SMartin Matuska        v["l2meta"] = cur["l2_bufc_metadata_asize"]
506*716fd348SMartin Matuska        v["l2pref%"] = 100 * v["l2pref"] // v["l2asize"]
507*716fd348SMartin Matuska        v["l2mfu%"] = 100 * v["l2mfu"] // v["l2asize"]
508*716fd348SMartin Matuska        v["l2mru%"] = 100 * v["l2mru"] // v["l2asize"]
509*716fd348SMartin Matuska        v["l2data%"] = 100 * v["l2data"] // v["l2asize"]
510*716fd348SMartin Matuska        v["l2meta%"] = 100 * v["l2meta"] // v["l2asize"]
511*716fd348SMartin Matuska
512*716fd348SMartin Matuska    v["grow"] = 0 if cur["arc_no_grow"] else 1
513*716fd348SMartin Matuska    v["need"] = cur["arc_need_free"]
514*716fd348SMartin Matuska    v["free"] = cur["memory_free_bytes"]
515*716fd348SMartin Matuska    v["avail"] = cur["memory_available_bytes"]
516*716fd348SMartin Matuska    v["waste"] = cur["abd_chunk_waste_size"]
517*716fd348SMartin Matuska
518*716fd348SMartin Matuska
519*716fd348SMartin Matuskadef main():
520*716fd348SMartin Matuska    global sint
521*716fd348SMartin Matuska    global count
522*716fd348SMartin Matuska    global hdr_intr
523*716fd348SMartin Matuska
524*716fd348SMartin Matuska    i = 0
525*716fd348SMartin Matuska    count_flag = 0
526*716fd348SMartin Matuska
527*716fd348SMartin Matuska    init()
528*716fd348SMartin Matuska    if count > 0:
529*716fd348SMartin Matuska        count_flag = 1
530*716fd348SMartin Matuska
531*716fd348SMartin Matuska    signal(SIGINT, SIG_DFL)
532*716fd348SMartin Matuska    signal(SIGWINCH, resize_handler)
533*716fd348SMartin Matuska    while True:
534*716fd348SMartin Matuska        if i == 0:
535*716fd348SMartin Matuska            print_header()
536*716fd348SMartin Matuska
537*716fd348SMartin Matuska        snap_stats()
538*716fd348SMartin Matuska        calculate()
539*716fd348SMartin Matuska        print_values()
540*716fd348SMartin Matuska
541*716fd348SMartin Matuska        if count_flag == 1:
542*716fd348SMartin Matuska            if count <= 1:
543*716fd348SMartin Matuska                break
544*716fd348SMartin Matuska            count -= 1
545*716fd348SMartin Matuska
546*716fd348SMartin Matuska        i = 0 if i >= hdr_intr else i + 1
547*716fd348SMartin Matuska        time.sleep(sint)
548*716fd348SMartin Matuska
549*716fd348SMartin Matuska    if out:
550*716fd348SMartin Matuska        out.close()
551*716fd348SMartin Matuska
552*716fd348SMartin Matuska
553*716fd348SMartin Matuskaif __name__ == '__main__':
554*716fd348SMartin Matuska    main()
555