xref: /freebsd-src/sys/contrib/openzfs/cmd/arcstat.in (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1716fd348SMartin Matuska#!/usr/bin/env @PYTHON_SHEBANG@
2716fd348SMartin Matuska#
3716fd348SMartin Matuska# Print out ZFS ARC Statistics exported via kstat(1)
4716fd348SMartin Matuska# For a definition of fields, or usage, use arcstat -v
5716fd348SMartin Matuska#
6716fd348SMartin Matuska# This script was originally a fork of the original arcstat.pl (0.1)
7716fd348SMartin Matuska# by Neelakanth Nadgir, originally published on his Sun blog on
8716fd348SMartin Matuska# 09/18/2007
9716fd348SMartin Matuska#     http://blogs.sun.com/realneel/entry/zfs_arc_statistics
10716fd348SMartin Matuska#
11716fd348SMartin Matuska# A new version aimed to improve upon the original by adding features
12716fd348SMartin Matuska# and fixing bugs as needed.  This version was maintained by Mike
13716fd348SMartin Matuska# Harsch and was hosted in a public open source repository:
14716fd348SMartin Matuska#    http://github.com/mharsch/arcstat
15716fd348SMartin Matuska#
16716fd348SMartin Matuska# but has since moved to the illumos-gate repository.
17716fd348SMartin Matuska#
18716fd348SMartin Matuska# This Python port was written by John Hixson for FreeNAS, introduced
19716fd348SMartin Matuska# in commit e2c29f:
20716fd348SMartin Matuska#    https://github.com/freenas/freenas
21716fd348SMartin Matuska#
22716fd348SMartin Matuska# and has been improved by many people since.
23716fd348SMartin Matuska#
24716fd348SMartin Matuska# CDDL HEADER START
25716fd348SMartin Matuska#
26716fd348SMartin Matuska# The contents of this file are subject to the terms of the
27716fd348SMartin Matuska# Common Development and Distribution License, Version 1.0 only
28716fd348SMartin Matuska# (the "License").  You may not use this file except in compliance
29716fd348SMartin Matuska# with the License.
30716fd348SMartin Matuska#
31716fd348SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
32271171e0SMartin Matuska# or https://opensource.org/licenses/CDDL-1.0.
33716fd348SMartin Matuska# See the License for the specific language governing permissions
34716fd348SMartin Matuska# and limitations under the License.
35716fd348SMartin Matuska#
36716fd348SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
37716fd348SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
38716fd348SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
39716fd348SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
40716fd348SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
41716fd348SMartin Matuska#
42716fd348SMartin Matuska# CDDL HEADER END
43716fd348SMartin Matuska#
44716fd348SMartin Matuska#
45716fd348SMartin Matuska# Fields have a fixed width. Every interval, we fill the "v"
46716fd348SMartin Matuska# hash with its corresponding value (v[field]=value) using calculate().
47716fd348SMartin Matuska# @hdr is the array of fields that needs to be printed, so we
48716fd348SMartin Matuska# just iterate over this array and print the values using our pretty printer.
49716fd348SMartin Matuska#
50716fd348SMartin Matuska# This script must remain compatible with Python 3.6+.
51716fd348SMartin Matuska#
52716fd348SMartin Matuska
53716fd348SMartin Matuskaimport sys
54716fd348SMartin Matuskaimport time
55716fd348SMartin Matuskaimport getopt
56716fd348SMartin Matuskaimport re
57716fd348SMartin Matuskaimport copy
58716fd348SMartin Matuska
59716fd348SMartin Matuskafrom signal import signal, SIGINT, SIGWINCH, SIG_DFL
60716fd348SMartin Matuska
61716fd348SMartin Matuska
62716fd348SMartin Matuskacols = {
63716fd348SMartin Matuska    # HDR:        [Size, Scale, Description]
64716fd348SMartin Matuska    "time":       [8, -1, "Time"],
6515f0b8c3SMartin Matuska    "hits":       [4, 1000, "ARC hits per second"],
6615f0b8c3SMartin Matuska    "iohs":       [4, 1000, "ARC I/O hits per second"],
67716fd348SMartin Matuska    "miss":       [4, 1000, "ARC misses per second"],
68716fd348SMartin Matuska    "read":       [4, 1000, "Total ARC accesses per second"],
69716fd348SMartin Matuska    "hit%":       [4, 100, "ARC hit percentage"],
7015f0b8c3SMartin Matuska    "ioh%":       [4, 100, "ARC I/O hit percentage"],
71716fd348SMartin Matuska    "miss%":      [5, 100, "ARC miss percentage"],
72716fd348SMartin Matuska    "dhit":       [4, 1000, "Demand hits per second"],
7315f0b8c3SMartin Matuska    "dioh":       [4, 1000, "Demand I/O hits per second"],
74716fd348SMartin Matuska    "dmis":       [4, 1000, "Demand misses per second"],
75716fd348SMartin Matuska    "dh%":        [3, 100, "Demand hit percentage"],
7615f0b8c3SMartin Matuska    "di%":        [3, 100, "Demand I/O hit percentage"],
77716fd348SMartin Matuska    "dm%":        [3, 100, "Demand miss percentage"],
7815f0b8c3SMartin Matuska    "ddhit":      [5, 1000, "Demand data hits per second"],
7915f0b8c3SMartin Matuska    "ddioh":      [5, 1000, "Demand data I/O hits per second"],
8015f0b8c3SMartin Matuska    "ddmis":      [5, 1000, "Demand data misses per second"],
8115f0b8c3SMartin Matuska    "ddh%":       [4, 100, "Demand data hit percentage"],
8215f0b8c3SMartin Matuska    "ddi%":       [4, 100, "Demand data I/O hit percentage"],
8315f0b8c3SMartin Matuska    "ddm%":       [4, 100, "Demand data miss percentage"],
8415f0b8c3SMartin Matuska    "dmhit":      [5, 1000, "Demand metadata hits per second"],
8515f0b8c3SMartin Matuska    "dmioh":      [5, 1000, "Demand metadata I/O hits per second"],
8615f0b8c3SMartin Matuska    "dmmis":      [5, 1000, "Demand metadata misses per second"],
8715f0b8c3SMartin Matuska    "dmh%":       [4, 100, "Demand metadata hit percentage"],
8815f0b8c3SMartin Matuska    "dmi%":       [4, 100, "Demand metadata I/O hit percentage"],
8915f0b8c3SMartin Matuska    "dmm%":       [4, 100, "Demand metadata miss percentage"],
90716fd348SMartin Matuska    "phit":       [4, 1000, "Prefetch hits per second"],
9115f0b8c3SMartin Matuska    "pioh":       [4, 1000, "Prefetch I/O hits per second"],
92716fd348SMartin Matuska    "pmis":       [4, 1000, "Prefetch misses per second"],
93716fd348SMartin Matuska    "ph%":        [3, 100, "Prefetch hits percentage"],
9415f0b8c3SMartin Matuska    "pi%":        [3, 100, "Prefetch I/O hits percentage"],
95716fd348SMartin Matuska    "pm%":        [3, 100, "Prefetch miss percentage"],
9615f0b8c3SMartin Matuska    "pdhit":      [5, 1000, "Prefetch data hits per second"],
9715f0b8c3SMartin Matuska    "pdioh":      [5, 1000, "Prefetch data I/O hits per second"],
9815f0b8c3SMartin Matuska    "pdmis":      [5, 1000, "Prefetch data misses per second"],
9915f0b8c3SMartin Matuska    "pdh%":       [4, 100, "Prefetch data hits percentage"],
10015f0b8c3SMartin Matuska    "pdi%":       [4, 100, "Prefetch data I/O hits percentage"],
10115f0b8c3SMartin Matuska    "pdm%":       [4, 100, "Prefetch data miss percentage"],
10215f0b8c3SMartin Matuska    "pmhit":      [5, 1000, "Prefetch metadata hits per second"],
10315f0b8c3SMartin Matuska    "pmioh":      [5, 1000, "Prefetch metadata I/O hits per second"],
10415f0b8c3SMartin Matuska    "pmmis":      [5, 1000, "Prefetch metadata misses per second"],
10515f0b8c3SMartin Matuska    "pmh%":       [4, 100, "Prefetch metadata hits percentage"],
10615f0b8c3SMartin Matuska    "pmi%":       [4, 100, "Prefetch metadata I/O hits percentage"],
10715f0b8c3SMartin Matuska    "pmm%":       [4, 100, "Prefetch metadata miss percentage"],
108716fd348SMartin Matuska    "mhit":       [4, 1000, "Metadata hits per second"],
10915f0b8c3SMartin Matuska    "mioh":       [4, 1000, "Metadata I/O hits per second"],
110716fd348SMartin Matuska    "mmis":       [4, 1000, "Metadata misses per second"],
111716fd348SMartin Matuska    "mread":      [5, 1000, "Metadata accesses per second"],
112716fd348SMartin Matuska    "mh%":        [3, 100, "Metadata hit percentage"],
11315f0b8c3SMartin Matuska    "mi%":        [3, 100, "Metadata I/O hit percentage"],
114716fd348SMartin Matuska    "mm%":        [3, 100, "Metadata miss percentage"],
115716fd348SMartin Matuska    "arcsz":      [5, 1024, "ARC size"],
11615f0b8c3SMartin Matuska    "size":       [5, 1024, "ARC size"],
11715f0b8c3SMartin Matuska    "c":          [5, 1024, "ARC target size"],
118716fd348SMartin Matuska    "mfu":        [4, 1000, "MFU list hits per second"],
119716fd348SMartin Matuska    "mru":        [4, 1000, "MRU list hits per second"],
120716fd348SMartin Matuska    "mfug":       [4, 1000, "MFU ghost list hits per second"],
121716fd348SMartin Matuska    "mrug":       [4, 1000, "MRU ghost list hits per second"],
12215f0b8c3SMartin Matuska    "unc":        [4, 1000, "Uncached list hits per second"],
123716fd348SMartin Matuska    "eskip":      [5, 1000, "evict_skip per second"],
124716fd348SMartin Matuska    "el2skip":    [7, 1000, "evict skip, due to l2 writes, per second"],
125716fd348SMartin Matuska    "el2cach":    [7, 1024, "Size of L2 cached evictions per second"],
126716fd348SMartin Matuska    "el2el":      [5, 1024, "Size of L2 eligible evictions per second"],
127716fd348SMartin Matuska    "el2mfu":     [6, 1024, "Size of L2 eligible MFU evictions per second"],
128716fd348SMartin Matuska    "el2mru":     [6, 1024, "Size of L2 eligible MRU evictions per second"],
129716fd348SMartin Matuska    "el2inel":    [7, 1024, "Size of L2 ineligible evictions per second"],
130716fd348SMartin Matuska    "mtxmis":     [6, 1000, "mutex_miss per second"],
131716fd348SMartin Matuska    "dread":      [5, 1000, "Demand accesses per second"],
13215f0b8c3SMartin Matuska    "ddread":     [6, 1000, "Demand data accesses per second"],
13315f0b8c3SMartin Matuska    "dmread":     [6, 1000, "Demand metadata accesses per second"],
134716fd348SMartin Matuska    "pread":      [5, 1000, "Prefetch accesses per second"],
13515f0b8c3SMartin Matuska    "pdread":     [6, 1000, "Prefetch data accesses per second"],
13615f0b8c3SMartin Matuska    "pmread":     [6, 1000, "Prefetch metadata accesses per second"],
137716fd348SMartin Matuska    "l2hits":     [6, 1000, "L2ARC hits per second"],
138716fd348SMartin Matuska    "l2miss":     [6, 1000, "L2ARC misses per second"],
139716fd348SMartin Matuska    "l2read":     [6, 1000, "Total L2ARC accesses per second"],
140716fd348SMartin Matuska    "l2hit%":     [6, 100, "L2ARC access hit percentage"],
141716fd348SMartin Matuska    "l2miss%":    [7, 100, "L2ARC access miss percentage"],
142716fd348SMartin Matuska    "l2pref":     [6, 1024, "L2ARC prefetch allocated size"],
143716fd348SMartin Matuska    "l2mfu":      [5, 1024, "L2ARC MFU allocated size"],
144716fd348SMartin Matuska    "l2mru":      [5, 1024, "L2ARC MRU allocated size"],
145716fd348SMartin Matuska    "l2data":     [6, 1024, "L2ARC data allocated size"],
146716fd348SMartin Matuska    "l2meta":     [6, 1024, "L2ARC metadata allocated size"],
147716fd348SMartin Matuska    "l2pref%":    [7, 100, "L2ARC prefetch percentage"],
148716fd348SMartin Matuska    "l2mfu%":     [6, 100, "L2ARC MFU percentage"],
149716fd348SMartin Matuska    "l2mru%":     [6, 100, "L2ARC MRU percentage"],
150716fd348SMartin Matuska    "l2data%":    [7, 100, "L2ARC data percentage"],
151716fd348SMartin Matuska    "l2meta%":    [7, 100, "L2ARC metadata percentage"],
152716fd348SMartin Matuska    "l2asize":    [7, 1024, "Actual (compressed) size of the L2ARC"],
153716fd348SMartin Matuska    "l2size":     [6, 1024, "Size of the L2ARC"],
154716fd348SMartin Matuska    "l2bytes":    [7, 1024, "Bytes read per second from the L2ARC"],
155*7a7741afSMartin Matuska    "l2wbytes":   [8, 1024, "Bytes written per second to the L2ARC"],
156716fd348SMartin Matuska    "grow":       [4, 1000, "ARC grow disabled"],
15715f0b8c3SMartin Matuska    "need":       [5, 1024, "ARC reclaim need"],
15815f0b8c3SMartin Matuska    "free":       [5, 1024, "ARC free memory"],
159716fd348SMartin Matuska    "avail":      [5, 1024, "ARC available memory"],
160716fd348SMartin Matuska    "waste":      [5, 1024, "Wasted memory due to round up to pagesize"],
1610d4ad640SMartin Matuska    "ztotal":     [6, 1000, "zfetch total prefetcher calls per second"],
1620d4ad640SMartin Matuska    "zhits":      [5, 1000, "zfetch stream hits per second"],
1630d4ad640SMartin Matuska    "zahead":     [6, 1000, "zfetch hits ahead of streams per second"],
1640d4ad640SMartin Matuska    "zpast":      [5, 1000, "zfetch hits behind streams per second"],
1650d4ad640SMartin Matuska    "zmisses":    [7, 1000, "zfetch stream misses per second"],
1660d4ad640SMartin Matuska    "zmax":       [4, 1000, "zfetch limit reached per second"],
1670d4ad640SMartin Matuska    "zfuture":    [7, 1000, "zfetch stream future per second"],
1680d4ad640SMartin Matuska    "zstride":    [7, 1000, "zfetch stream strides per second"],
1690d4ad640SMartin Matuska    "zissued":    [7, 1000, "zfetch prefetches issued per second"],
1700d4ad640SMartin Matuska    "zactive":    [7, 1000, "zfetch prefetches active per second"],
171716fd348SMartin Matuska}
172716fd348SMartin Matuska
173*7a7741afSMartin Matuska# ARC structural breakdown from arc_summary
174*7a7741afSMartin Matuskastructfields = {
175*7a7741afSMartin Matuska    "cmp":      ["compressed", "Compressed"],
176*7a7741afSMartin Matuska    "ovh":      ["overhead", "Overhead"],
177*7a7741afSMartin Matuska    "bon":      ["bonus", "Bonus"],
178*7a7741afSMartin Matuska    "dno":      ["dnode", "Dnode"],
179*7a7741afSMartin Matuska    "dbu":      ["dbuf", "Dbuf"],
180*7a7741afSMartin Matuska    "hdr":      ["hdr", "Header"],
181*7a7741afSMartin Matuska    "l2h":      ["l2_hdr", "L2 header"],
182*7a7741afSMartin Matuska    "abd":      ["abd_chunk_waste", "ABD chunk waste"],
183*7a7741afSMartin Matuska}
184*7a7741afSMartin Matuskastructstats = {                             # size stats
185*7a7741afSMartin Matuska    "percent":  "size",                     # percentage of this value
186*7a7741afSMartin Matuska    "sz":       ["_size", "size"],
187*7a7741afSMartin Matuska}
188*7a7741afSMartin Matuska
189*7a7741afSMartin Matuska# ARC types breakdown from arc_summary
190*7a7741afSMartin Matuskatypefields = {
191*7a7741afSMartin Matuska    "data":     ["data", "ARC data"],
192*7a7741afSMartin Matuska    "meta":     ["metadata", "ARC metadata"],
193*7a7741afSMartin Matuska}
194*7a7741afSMartin Matuskatypestats = {                               # size stats
195*7a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
196*7a7741afSMartin Matuska    "tg":       ["_target", "target"],
197*7a7741afSMartin Matuska    "sz":       ["_size", "size"],
198*7a7741afSMartin Matuska}
199*7a7741afSMartin Matuska
200*7a7741afSMartin Matuska# ARC states breakdown from arc_summary
201*7a7741afSMartin Matuskastatefields = {
202*7a7741afSMartin Matuska    "ano":      ["anon", "Anonymous"],
203*7a7741afSMartin Matuska    "mfu":      ["mfu", "MFU"],
204*7a7741afSMartin Matuska    "mru":      ["mru", "MRU"],
205*7a7741afSMartin Matuska    "unc":      ["uncached", "Uncached"],
206*7a7741afSMartin Matuska}
207*7a7741afSMartin Matuskatargetstats = {
208*7a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
209*7a7741afSMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
210*7a7741afSMartin Matuska    "tg":       ["_target", "target"],
211*7a7741afSMartin Matuska    "dt":       ["_data_target", "data target"],
212*7a7741afSMartin Matuska    "mt":       ["_metadata_target", "metadata target"],
213*7a7741afSMartin Matuska}
214*7a7741afSMartin Matuskastatestats = {                              # size stats
215*7a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
216*7a7741afSMartin Matuska    "sz":       ["_size", "size"],
217*7a7741afSMartin Matuska    "da":       ["_data", "data size"],
218*7a7741afSMartin Matuska    "me":       ["_metadata", "metadata size"],
219*7a7741afSMartin Matuska    "ed":       ["_evictable_data", "evictable data size"],
220*7a7741afSMartin Matuska    "em":       ["_evictable_metadata", "evictable metadata size"],
221*7a7741afSMartin Matuska}
222*7a7741afSMartin Matuskaghoststats = {
223*7a7741afSMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
224*7a7741afSMartin Matuska    "gsz":      ["_ghost_size", "ghost size"],
225*7a7741afSMartin Matuska    "gd":       ["_ghost_data", "ghost data size"],
226*7a7741afSMartin Matuska    "gm":       ["_ghost_metadata", "ghost metadata size"],
227*7a7741afSMartin Matuska}
228*7a7741afSMartin Matuska
229*7a7741afSMartin Matuska# fields and stats
230*7a7741afSMartin Matuskafieldstats = [
231*7a7741afSMartin Matuska    [structfields, structstats],
232*7a7741afSMartin Matuska    [typefields, typestats],
233*7a7741afSMartin Matuska    [statefields, targetstats, statestats, ghoststats],
234*7a7741afSMartin Matuska]
235*7a7741afSMartin Matuskafor fs in fieldstats:
236*7a7741afSMartin Matuska    fields, stats = fs[0], fs[1:]
237*7a7741afSMartin Matuska    for field, fieldval in fields.items():
238*7a7741afSMartin Matuska        for group in stats:
239*7a7741afSMartin Matuska            for stat, statval in group.items():
240*7a7741afSMartin Matuska                if stat in ["fields", "percent"] or \
241*7a7741afSMartin Matuska                    ("fields" in group and field not in group["fields"]):
242*7a7741afSMartin Matuska                    continue
243*7a7741afSMartin Matuska                colname = field + stat
244*7a7741afSMartin Matuska                coldesc = fieldval[1] + " " + statval[1]
245*7a7741afSMartin Matuska                cols[colname] = [len(colname), 1024, coldesc]
246*7a7741afSMartin Matuska                if "percent" in group:
247*7a7741afSMartin Matuska                    cols[colname + "%"] = [len(colname) + 1, 100, \
248*7a7741afSMartin Matuska                        coldesc + " percentage"]
249*7a7741afSMartin Matuska
250716fd348SMartin Matuskav = {}
25115f0b8c3SMartin Matuskahdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%",
25215f0b8c3SMartin Matuska       "size", "c", "avail"]
25315f0b8c3SMartin Matuskaxhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis",
25415f0b8c3SMartin Matuska        "dread", "pread", "read"]
2550d4ad640SMartin Matuskazhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax",
2560d4ad640SMartin Matuska        "zfuture", "zstride", "zissued", "zactive"]
257716fd348SMartin Matuskasint = 1               # Default interval is 1 second
258716fd348SMartin Matuskacount = 1              # Default count is 1
259716fd348SMartin Matuskahdr_intr = 20          # Print header every 20 lines of output
260716fd348SMartin Matuskaopfile = None
261716fd348SMartin Matuskasep = "  "              # Default separator is 2 spaces
262716fd348SMartin Matuskal2exist = False
263716fd348SMartin Matuskacmd = ("Usage: arcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
264716fd348SMartin Matuska       "[count]]\n")
265716fd348SMartin Matuskacur = {}
266716fd348SMartin Matuskad = {}
267716fd348SMartin Matuskaout = None
268716fd348SMartin Matuskakstat = None
269716fd348SMartin Matuskapretty_print = True
270716fd348SMartin Matuska
271716fd348SMartin Matuska
272716fd348SMartin Matuskaif sys.platform.startswith('freebsd'):
273716fd348SMartin Matuska    # Requires py-sysctl on FreeBSD
274716fd348SMartin Matuska    import sysctl
275716fd348SMartin Matuska
276716fd348SMartin Matuska    def kstat_update():
277716fd348SMartin Matuska        global kstat
278716fd348SMartin Matuska
279716fd348SMartin Matuska        k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats')
280716fd348SMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
281b985c9caSMartin Matuska        k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats')
282b985c9caSMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
283716fd348SMartin Matuska
284716fd348SMartin Matuska        if not k:
285716fd348SMartin Matuska            sys.exit(1)
286716fd348SMartin Matuska
287716fd348SMartin Matuska        kstat = {}
288716fd348SMartin Matuska
289716fd348SMartin Matuska        for s in k:
290716fd348SMartin Matuska            if not s:
291716fd348SMartin Matuska                continue
292716fd348SMartin Matuska
293716fd348SMartin Matuska            name, value = s.name, s.value
294b985c9caSMartin Matuska
295b985c9caSMartin Matuska            if "arcstats" in name:
296716fd348SMartin Matuska                # Trims 'kstat.zfs.misc.arcstats' from the name
297716fd348SMartin Matuska                kstat[name[24:]] = int(value)
298b985c9caSMartin Matuska            else:
299b985c9caSMartin Matuska                kstat["zfetch_" + name[27:]] = int(value)
300716fd348SMartin Matuska
301716fd348SMartin Matuskaelif sys.platform.startswith('linux'):
302716fd348SMartin Matuska    def kstat_update():
303716fd348SMartin Matuska        global kstat
304716fd348SMartin Matuska
3050d4ad640SMartin Matuska        k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
306716fd348SMartin Matuska
3070d4ad640SMartin Matuska        k2 = ["zfetch_" + line.strip() for line in
3080d4ad640SMartin Matuska             open('/proc/spl/kstat/zfs/zfetchstats')]
3090d4ad640SMartin Matuska
3100d4ad640SMartin Matuska        if k1 is None or k2 is None:
311716fd348SMartin Matuska            sys.exit(1)
312716fd348SMartin Matuska
3130d4ad640SMartin Matuska        del k1[0:2]
3140d4ad640SMartin Matuska        del k2[0:2]
3150d4ad640SMartin Matuska        k = k1 + k2
316716fd348SMartin Matuska        kstat = {}
317716fd348SMartin Matuska
318716fd348SMartin Matuska        for s in k:
319716fd348SMartin Matuska            if not s:
320716fd348SMartin Matuska                continue
321716fd348SMartin Matuska
322716fd348SMartin Matuska            name, unused, value = s.split()
323716fd348SMartin Matuska            kstat[name] = int(value)
324716fd348SMartin Matuska
325716fd348SMartin Matuska
326716fd348SMartin Matuskadef detailed_usage():
327716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
328716fd348SMartin Matuska    sys.stderr.write("Field definitions are as follows:\n")
329716fd348SMartin Matuska    for key in cols:
330716fd348SMartin Matuska        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
331716fd348SMartin Matuska    sys.stderr.write("\n")
332716fd348SMartin Matuska
333716fd348SMartin Matuska    sys.exit(0)
334716fd348SMartin Matuska
335716fd348SMartin Matuska
336716fd348SMartin Matuskadef usage():
337716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
338716fd348SMartin Matuska    sys.stderr.write("\t -h : Print this help message\n")
339716fd348SMartin Matuska    sys.stderr.write("\t -a : Print all possible stats\n")
340716fd348SMartin Matuska    sys.stderr.write("\t -v : List all possible field headers and definitions"
341716fd348SMartin Matuska                     "\n")
342716fd348SMartin Matuska    sys.stderr.write("\t -x : Print extended stats\n")
3430d4ad640SMartin Matuska    sys.stderr.write("\t -z : Print zfetch stats\n")
344716fd348SMartin Matuska    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
345716fd348SMartin Matuska    sys.stderr.write("\t -o : Redirect output to the specified file\n")
346716fd348SMartin Matuska    sys.stderr.write("\t -s : Override default field separator with custom "
347716fd348SMartin Matuska                     "character or string\n")
348716fd348SMartin Matuska    sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n")
349716fd348SMartin Matuska    sys.stderr.write("\nExamples:\n")
350716fd348SMartin Matuska    sys.stderr.write("\tarcstat -o /tmp/a.log 2 10\n")
351716fd348SMartin Matuska    sys.stderr.write("\tarcstat -s \",\" -o /tmp/a.log 2 10\n")
352716fd348SMartin Matuska    sys.stderr.write("\tarcstat -v\n")
353716fd348SMartin Matuska    sys.stderr.write("\tarcstat -f time,hit%,dh%,ph%,mh% 1\n")
354716fd348SMartin Matuska    sys.stderr.write("\n")
355716fd348SMartin Matuska
356716fd348SMartin Matuska    sys.exit(1)
357716fd348SMartin Matuska
358716fd348SMartin Matuska
359716fd348SMartin Matuskadef snap_stats():
360716fd348SMartin Matuska    global cur
361716fd348SMartin Matuska    global kstat
362716fd348SMartin Matuska
363716fd348SMartin Matuska    prev = copy.deepcopy(cur)
364716fd348SMartin Matuska    kstat_update()
365716fd348SMartin Matuska
366716fd348SMartin Matuska    cur = kstat
367*7a7741afSMartin Matuska
368*7a7741afSMartin Matuska    # fill in additional values from arc_summary
369*7a7741afSMartin Matuska    cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\
370*7a7741afSMartin Matuska        cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\
371*7a7741afSMartin Matuska        cur["uncached_data"]+cur["uncached_metadata"]
372*7a7741afSMartin Matuska    s = 4294967296
373*7a7741afSMartin Matuska    pd = cur["pd"]
374*7a7741afSMartin Matuska    pm = cur["pm"]
375*7a7741afSMartin Matuska    meta = cur["meta"]
376*7a7741afSMartin Matuska    v = (s-int(pd))*(s-int(meta))/s
377*7a7741afSMartin Matuska    cur["mfu_data_target"] = v / 65536 * caches_size / 65536
378*7a7741afSMartin Matuska    v = (s-int(pm))*int(meta)/s
379*7a7741afSMartin Matuska    cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536
380*7a7741afSMartin Matuska    v = int(pd)*(s-int(meta))/s
381*7a7741afSMartin Matuska    cur["mru_data_target"] = v / 65536 * caches_size / 65536
382*7a7741afSMartin Matuska    v = int(pm)*int(meta)/s
383*7a7741afSMartin Matuska    cur["mru_metadata_target"] = v / 65536 * caches_size / 65536
384*7a7741afSMartin Matuska
385*7a7741afSMartin Matuska    cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"]
386*7a7741afSMartin Matuska    cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"]
387*7a7741afSMartin Matuska    cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"]
388*7a7741afSMartin Matuska    cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"]
389*7a7741afSMartin Matuska
390716fd348SMartin Matuska    for key in cur:
391716fd348SMartin Matuska        if re.match(key, "class"):
392716fd348SMartin Matuska            continue
393716fd348SMartin Matuska        if key in prev:
394716fd348SMartin Matuska            d[key] = cur[key] - prev[key]
395716fd348SMartin Matuska        else:
396716fd348SMartin Matuska            d[key] = cur[key]
397716fd348SMartin Matuska
398716fd348SMartin Matuska
399*7a7741afSMartin Matuskadef isint(num):
400*7a7741afSMartin Matuska    if isinstance(num, float):
401*7a7741afSMartin Matuska        return num.is_integer()
402*7a7741afSMartin Matuska    if isinstance(num, int):
403*7a7741afSMartin Matuska        return True
404*7a7741afSMartin Matuska    return False
405*7a7741afSMartin Matuska
406*7a7741afSMartin Matuska
407716fd348SMartin Matuskadef prettynum(sz, scale, num=0):
408716fd348SMartin Matuska    suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
409716fd348SMartin Matuska    index = 0
410716fd348SMartin Matuska
411716fd348SMartin Matuska    # Special case for date field
412716fd348SMartin Matuska    if scale == -1:
413716fd348SMartin Matuska        return "%s" % num
414716fd348SMartin Matuska
415*7a7741afSMartin Matuska    if scale != 100:
416716fd348SMartin Matuska        while abs(num) > scale and index < 5:
417716fd348SMartin Matuska            num = num / scale
418716fd348SMartin Matuska            index += 1
419716fd348SMartin Matuska
420*7a7741afSMartin Matuska    width = sz - (0 if index == 0 else 1)
421*7a7741afSMartin Matuska    intlen = len("%.0f" % num)              # %.0f rounds to nearest int
422*7a7741afSMartin Matuska    if sint == 1 and isint(num) or width < intlen + 2:
423*7a7741afSMartin Matuska        decimal = 0
424716fd348SMartin Matuska    else:
425*7a7741afSMartin Matuska        decimal = 1
426*7a7741afSMartin Matuska    return "%*.*f%s" % (width, decimal, num, suffix[index])
427716fd348SMartin Matuska
428716fd348SMartin Matuska
429716fd348SMartin Matuskadef print_values():
430716fd348SMartin Matuska    global hdr
431716fd348SMartin Matuska    global sep
432716fd348SMartin Matuska    global v
433716fd348SMartin Matuska    global pretty_print
434716fd348SMartin Matuska
435716fd348SMartin Matuska    if pretty_print:
436716fd348SMartin Matuska        fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
437716fd348SMartin Matuska    else:
43808aba0aeSMartin Matuska        fmt = lambda col: str(v[col])
439716fd348SMartin Matuska
440716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
441716fd348SMartin Matuska    sys.stdout.write("\n")
442716fd348SMartin Matuska    sys.stdout.flush()
443716fd348SMartin Matuska
444716fd348SMartin Matuska
445716fd348SMartin Matuskadef print_header():
446716fd348SMartin Matuska    global hdr
447716fd348SMartin Matuska    global sep
448716fd348SMartin Matuska    global pretty_print
449716fd348SMartin Matuska
450716fd348SMartin Matuska    if pretty_print:
451716fd348SMartin Matuska        fmt = lambda col: "%*s" % (cols[col][0], col)
452716fd348SMartin Matuska    else:
453716fd348SMartin Matuska        fmt = lambda col: col
454716fd348SMartin Matuska
455716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
456716fd348SMartin Matuska    sys.stdout.write("\n")
457716fd348SMartin Matuska
458716fd348SMartin Matuska
459716fd348SMartin Matuskadef get_terminal_lines():
460716fd348SMartin Matuska    try:
461716fd348SMartin Matuska        import fcntl
462716fd348SMartin Matuska        import termios
463716fd348SMartin Matuska        import struct
464716fd348SMartin Matuska        data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
465716fd348SMartin Matuska        sz = struct.unpack('hh', data)
466716fd348SMartin Matuska        return sz[0]
467716fd348SMartin Matuska    except Exception:
468716fd348SMartin Matuska        pass
469716fd348SMartin Matuska
470716fd348SMartin Matuska
471716fd348SMartin Matuskadef update_hdr_intr():
472716fd348SMartin Matuska    global hdr_intr
473716fd348SMartin Matuska
474716fd348SMartin Matuska    lines = get_terminal_lines()
475716fd348SMartin Matuska    if lines and lines > 3:
476716fd348SMartin Matuska        hdr_intr = lines - 3
477716fd348SMartin Matuska
478716fd348SMartin Matuska
479716fd348SMartin Matuskadef resize_handler(signum, frame):
480716fd348SMartin Matuska    update_hdr_intr()
481716fd348SMartin Matuska
482716fd348SMartin Matuska
483716fd348SMartin Matuskadef init():
484716fd348SMartin Matuska    global sint
485716fd348SMartin Matuska    global count
486716fd348SMartin Matuska    global hdr
487716fd348SMartin Matuska    global xhdr
4880d4ad640SMartin Matuska    global zhdr
489716fd348SMartin Matuska    global opfile
490716fd348SMartin Matuska    global sep
491716fd348SMartin Matuska    global out
492716fd348SMartin Matuska    global l2exist
493716fd348SMartin Matuska    global pretty_print
494716fd348SMartin Matuska
495716fd348SMartin Matuska    desired_cols = None
496716fd348SMartin Matuska    aflag = False
497716fd348SMartin Matuska    xflag = False
498716fd348SMartin Matuska    hflag = False
499716fd348SMartin Matuska    vflag = False
5000d4ad640SMartin Matuska    zflag = False
501716fd348SMartin Matuska    i = 1
502716fd348SMartin Matuska
503716fd348SMartin Matuska    try:
504716fd348SMartin Matuska        opts, args = getopt.getopt(
505716fd348SMartin Matuska            sys.argv[1:],
5060d4ad640SMartin Matuska            "axzo:hvs:f:p",
507716fd348SMartin Matuska            [
508716fd348SMartin Matuska                "all",
509716fd348SMartin Matuska                "extended",
5100d4ad640SMartin Matuska                "zfetch",
511716fd348SMartin Matuska                "outfile",
512716fd348SMartin Matuska                "help",
513716fd348SMartin Matuska                "verbose",
514716fd348SMartin Matuska                "separator",
515716fd348SMartin Matuska                "columns",
516716fd348SMartin Matuska                "parsable"
517716fd348SMartin Matuska            ]
518716fd348SMartin Matuska        )
519716fd348SMartin Matuska    except getopt.error as msg:
520716fd348SMartin Matuska        sys.stderr.write("Error: %s\n" % str(msg))
521716fd348SMartin Matuska        usage()
522716fd348SMartin Matuska        opts = None
523716fd348SMartin Matuska
524716fd348SMartin Matuska    for opt, arg in opts:
525716fd348SMartin Matuska        if opt in ('-a', '--all'):
526716fd348SMartin Matuska            aflag = True
527716fd348SMartin Matuska        if opt in ('-x', '--extended'):
528716fd348SMartin Matuska            xflag = True
529716fd348SMartin Matuska        if opt in ('-o', '--outfile'):
530716fd348SMartin Matuska            opfile = arg
531716fd348SMartin Matuska            i += 1
532716fd348SMartin Matuska        if opt in ('-h', '--help'):
533716fd348SMartin Matuska            hflag = True
534716fd348SMartin Matuska        if opt in ('-v', '--verbose'):
535716fd348SMartin Matuska            vflag = True
536716fd348SMartin Matuska        if opt in ('-s', '--separator'):
537716fd348SMartin Matuska            sep = arg
538716fd348SMartin Matuska            i += 1
539716fd348SMartin Matuska        if opt in ('-f', '--columns'):
540716fd348SMartin Matuska            desired_cols = arg
541716fd348SMartin Matuska            i += 1
542716fd348SMartin Matuska        if opt in ('-p', '--parsable'):
543716fd348SMartin Matuska            pretty_print = False
5440d4ad640SMartin Matuska        if opt in ('-z', '--zfetch'):
5450d4ad640SMartin Matuska            zflag = True
546716fd348SMartin Matuska        i += 1
547716fd348SMartin Matuska
548716fd348SMartin Matuska    argv = sys.argv[i:]
549716fd348SMartin Matuska    sint = int(argv[0]) if argv else sint
550716fd348SMartin Matuska    count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1)
551716fd348SMartin Matuska
5520d4ad640SMartin Matuska    if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols):
553716fd348SMartin Matuska        usage()
554716fd348SMartin Matuska
555716fd348SMartin Matuska    if vflag:
556716fd348SMartin Matuska        detailed_usage()
557716fd348SMartin Matuska
558716fd348SMartin Matuska    if xflag:
559716fd348SMartin Matuska        hdr = xhdr
560716fd348SMartin Matuska
5610d4ad640SMartin Matuska    if zflag:
5620d4ad640SMartin Matuska        hdr = zhdr
5630d4ad640SMartin Matuska
564716fd348SMartin Matuska    update_hdr_intr()
565716fd348SMartin Matuska
566716fd348SMartin Matuska    # check if L2ARC exists
567716fd348SMartin Matuska    snap_stats()
568716fd348SMartin Matuska    l2_size = cur.get("l2_size")
569716fd348SMartin Matuska    if l2_size:
570716fd348SMartin Matuska        l2exist = True
571716fd348SMartin Matuska
572716fd348SMartin Matuska    if desired_cols:
573716fd348SMartin Matuska        hdr = desired_cols.split(",")
574716fd348SMartin Matuska
575716fd348SMartin Matuska        invalid = []
576716fd348SMartin Matuska        incompat = []
577716fd348SMartin Matuska        for ele in hdr:
578716fd348SMartin Matuska            if ele not in cols:
579716fd348SMartin Matuska                invalid.append(ele)
580716fd348SMartin Matuska            elif not l2exist and ele.startswith("l2"):
581716fd348SMartin Matuska                sys.stdout.write("No L2ARC Here\n%s\n" % ele)
582716fd348SMartin Matuska                incompat.append(ele)
583716fd348SMartin Matuska
584716fd348SMartin Matuska        if len(invalid) > 0:
585716fd348SMartin Matuska            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
586716fd348SMartin Matuska            usage()
587716fd348SMartin Matuska
588716fd348SMartin Matuska        if len(incompat) > 0:
589716fd348SMartin Matuska            sys.stderr.write("Incompatible field specified! -- %s\n" %
590716fd348SMartin Matuska                             incompat)
591716fd348SMartin Matuska            usage()
592716fd348SMartin Matuska
593716fd348SMartin Matuska    if aflag:
594716fd348SMartin Matuska        if l2exist:
595716fd348SMartin Matuska            hdr = cols.keys()
596716fd348SMartin Matuska        else:
597716fd348SMartin Matuska            hdr = [col for col in cols.keys() if not col.startswith("l2")]
598716fd348SMartin Matuska
599716fd348SMartin Matuska    if opfile:
600716fd348SMartin Matuska        try:
601716fd348SMartin Matuska            out = open(opfile, "w")
602716fd348SMartin Matuska            sys.stdout = out
603716fd348SMartin Matuska
604716fd348SMartin Matuska        except IOError:
605716fd348SMartin Matuska            sys.stderr.write("Cannot open %s for writing\n" % opfile)
606716fd348SMartin Matuska            sys.exit(1)
607716fd348SMartin Matuska
608716fd348SMartin Matuska
609716fd348SMartin Matuskadef calculate():
610716fd348SMartin Matuska    global d
611716fd348SMartin Matuska    global v
612716fd348SMartin Matuska    global l2exist
613716fd348SMartin Matuska
614716fd348SMartin Matuska    v = dict()
615716fd348SMartin Matuska    v["time"] = time.strftime("%H:%M:%S", time.localtime())
616*7a7741afSMartin Matuska    v["hits"] = d["hits"] / sint
617*7a7741afSMartin Matuska    v["iohs"] = d["iohits"] / sint
618*7a7741afSMartin Matuska    v["miss"] = d["misses"] / sint
61915f0b8c3SMartin Matuska    v["read"] = v["hits"] + v["iohs"] + v["miss"]
620*7a7741afSMartin Matuska    v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0
621*7a7741afSMartin Matuska    v["ioh%"] = 100 * v["iohs"] / v["read"] if v["read"] > 0 else 0
62215f0b8c3SMartin Matuska    v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0
623716fd348SMartin Matuska
624*7a7741afSMartin Matuska    v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint
625*7a7741afSMartin Matuska    v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) / sint
626*7a7741afSMartin Matuska    v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
627716fd348SMartin Matuska
62815f0b8c3SMartin Matuska    v["dread"] = v["dhit"] + v["dioh"] + v["dmis"]
629*7a7741afSMartin Matuska    v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0
630*7a7741afSMartin Matuska    v["di%"] = 100 * v["dioh"] / v["dread"] if v["dread"] > 0 else 0
63115f0b8c3SMartin Matuska    v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0
63215f0b8c3SMartin Matuska
633*7a7741afSMartin Matuska    v["ddhit"] = d["demand_data_hits"] / sint
634*7a7741afSMartin Matuska    v["ddioh"] = d["demand_data_iohits"] / sint
635*7a7741afSMartin Matuska    v["ddmis"] = d["demand_data_misses"] / sint
63615f0b8c3SMartin Matuska
63715f0b8c3SMartin Matuska    v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"]
638*7a7741afSMartin Matuska    v["ddh%"] = 100 * v["ddhit"] / v["ddread"] if v["ddread"] > 0 else 0
639*7a7741afSMartin Matuska    v["ddi%"] = 100 * v["ddioh"] / v["ddread"] if v["ddread"] > 0 else 0
64015f0b8c3SMartin Matuska    v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0
64115f0b8c3SMartin Matuska
642*7a7741afSMartin Matuska    v["dmhit"] = d["demand_metadata_hits"] / sint
643*7a7741afSMartin Matuska    v["dmioh"] = d["demand_metadata_iohits"] / sint
644*7a7741afSMartin Matuska    v["dmmis"] = d["demand_metadata_misses"] / sint
64515f0b8c3SMartin Matuska
64615f0b8c3SMartin Matuska    v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"]
647*7a7741afSMartin Matuska    v["dmh%"] = 100 * v["dmhit"] / v["dmread"] if v["dmread"] > 0 else 0
648*7a7741afSMartin Matuska    v["dmi%"] = 100 * v["dmioh"] / v["dmread"] if v["dmread"] > 0 else 0
64915f0b8c3SMartin Matuska    v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0
650716fd348SMartin Matuska
651*7a7741afSMartin Matuska    v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
65215f0b8c3SMartin Matuska    v["pioh"] = (d["prefetch_data_iohits"] +
653*7a7741afSMartin Matuska                 d["prefetch_metadata_iohits"]) / sint
654716fd348SMartin Matuska    v["pmis"] = (d["prefetch_data_misses"] +
655*7a7741afSMartin Matuska                 d["prefetch_metadata_misses"]) / sint
656716fd348SMartin Matuska
65715f0b8c3SMartin Matuska    v["pread"] = v["phit"] + v["pioh"] + v["pmis"]
658*7a7741afSMartin Matuska    v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0
659*7a7741afSMartin Matuska    v["pi%"] = 100 * v["pioh"] / v["pread"] if v["pread"] > 0 else 0
66015f0b8c3SMartin Matuska    v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0
66115f0b8c3SMartin Matuska
662*7a7741afSMartin Matuska    v["pdhit"] = d["prefetch_data_hits"] / sint
663*7a7741afSMartin Matuska    v["pdioh"] = d["prefetch_data_iohits"] / sint
664*7a7741afSMartin Matuska    v["pdmis"] = d["prefetch_data_misses"] / sint
66515f0b8c3SMartin Matuska
66615f0b8c3SMartin Matuska    v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"]
667*7a7741afSMartin Matuska    v["pdh%"] = 100 * v["pdhit"] / v["pdread"] if v["pdread"] > 0 else 0
668*7a7741afSMartin Matuska    v["pdi%"] = 100 * v["pdioh"] / v["pdread"] if v["pdread"] > 0 else 0
66915f0b8c3SMartin Matuska    v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0
67015f0b8c3SMartin Matuska
671*7a7741afSMartin Matuska    v["pmhit"] = d["prefetch_metadata_hits"] / sint
672*7a7741afSMartin Matuska    v["pmioh"] = d["prefetch_metadata_iohits"] / sint
673*7a7741afSMartin Matuska    v["pmmis"] = d["prefetch_metadata_misses"] / sint
67415f0b8c3SMartin Matuska
67515f0b8c3SMartin Matuska    v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"]
676*7a7741afSMartin Matuska    v["pmh%"] = 100 * v["pmhit"] / v["pmread"] if v["pmread"] > 0 else 0
677*7a7741afSMartin Matuska    v["pmi%"] = 100 * v["pmioh"] / v["pmread"] if v["pmread"] > 0 else 0
67815f0b8c3SMartin Matuska    v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0
679716fd348SMartin Matuska
680716fd348SMartin Matuska    v["mhit"] = (d["prefetch_metadata_hits"] +
681*7a7741afSMartin Matuska                 d["demand_metadata_hits"]) / sint
68215f0b8c3SMartin Matuska    v["mioh"] = (d["prefetch_metadata_iohits"] +
683*7a7741afSMartin Matuska                 d["demand_metadata_iohits"]) / sint
684716fd348SMartin Matuska    v["mmis"] = (d["prefetch_metadata_misses"] +
685*7a7741afSMartin Matuska                 d["demand_metadata_misses"]) / sint
686716fd348SMartin Matuska
68715f0b8c3SMartin Matuska    v["mread"] = v["mhit"] + v["mioh"] + v["mmis"]
688*7a7741afSMartin Matuska    v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0
689*7a7741afSMartin Matuska    v["mi%"] = 100 * v["mioh"] / v["mread"] if v["mread"] > 0 else 0
69015f0b8c3SMartin Matuska    v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0
691716fd348SMartin Matuska
692716fd348SMartin Matuska    v["arcsz"] = cur["size"]
693716fd348SMartin Matuska    v["size"] = cur["size"]
694716fd348SMartin Matuska    v["c"] = cur["c"]
695*7a7741afSMartin Matuska    v["mfu"] = d["mfu_hits"] / sint
696*7a7741afSMartin Matuska    v["mru"] = d["mru_hits"] / sint
697*7a7741afSMartin Matuska    v["mrug"] = d["mru_ghost_hits"] / sint
698*7a7741afSMartin Matuska    v["mfug"] = d["mfu_ghost_hits"] / sint
699*7a7741afSMartin Matuska    v["unc"] = d["uncached_hits"] / sint
700*7a7741afSMartin Matuska    v["eskip"] = d["evict_skip"] / sint
701*7a7741afSMartin Matuska    v["el2skip"] = d["evict_l2_skip"] / sint
702*7a7741afSMartin Matuska    v["el2cach"] = d["evict_l2_cached"] / sint
703*7a7741afSMartin Matuska    v["el2el"] = d["evict_l2_eligible"] / sint
704*7a7741afSMartin Matuska    v["el2mfu"] = d["evict_l2_eligible_mfu"] / sint
705*7a7741afSMartin Matuska    v["el2mru"] = d["evict_l2_eligible_mru"] / sint
706*7a7741afSMartin Matuska    v["el2inel"] = d["evict_l2_ineligible"] / sint
707*7a7741afSMartin Matuska    v["mtxmis"] = d["mutex_miss"] / sint
7080d4ad640SMartin Matuska    v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] +
709*7a7741afSMartin Matuska                   d["zfetch_past"] + d["zfetch_misses"]) / sint
710*7a7741afSMartin Matuska    v["zhits"] = d["zfetch_hits"] / sint
711*7a7741afSMartin Matuska    v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) / sint
712*7a7741afSMartin Matuska    v["zpast"] = d["zfetch_past"] / sint
713*7a7741afSMartin Matuska    v["zmisses"] = d["zfetch_misses"] / sint
714*7a7741afSMartin Matuska    v["zmax"] = d["zfetch_max_streams"] / sint
715*7a7741afSMartin Matuska    v["zfuture"] = d["zfetch_future"] / sint
716*7a7741afSMartin Matuska    v["zstride"] = d["zfetch_stride"] / sint
717*7a7741afSMartin Matuska    v["zissued"] = d["zfetch_io_issued"] / sint
718*7a7741afSMartin Matuska    v["zactive"] = d["zfetch_io_active"] / sint
719*7a7741afSMartin Matuska
720*7a7741afSMartin Matuska    # ARC structural breakdown, ARC types breakdown, ARC states breakdown
721*7a7741afSMartin Matuska    v["cachessz"] = cur["caches_size"]
722*7a7741afSMartin Matuska    for fs in fieldstats:
723*7a7741afSMartin Matuska        fields, stats = fs[0], fs[1:]
724*7a7741afSMartin Matuska        for field, fieldval in fields.items():
725*7a7741afSMartin Matuska            for group in stats:
726*7a7741afSMartin Matuska                for stat, statval in group.items():
727*7a7741afSMartin Matuska                    if stat in ["fields", "percent"] or \
728*7a7741afSMartin Matuska                        ("fields" in group and field not in group["fields"]):
729*7a7741afSMartin Matuska                        continue
730*7a7741afSMartin Matuska                    colname = field + stat
731*7a7741afSMartin Matuska                    v[colname] = cur[fieldval[0] + statval[0]]
732*7a7741afSMartin Matuska                    if "percent" in group:
733*7a7741afSMartin Matuska                        v[colname + "%"] = 100 * v[colname] / \
734*7a7741afSMartin Matuska                            v[group["percent"]] if v[group["percent"]] > 0 else 0
735716fd348SMartin Matuska
736716fd348SMartin Matuska    if l2exist:
737*7a7741afSMartin Matuska        v["l2hits"] = d["l2_hits"] / sint
738*7a7741afSMartin Matuska        v["l2miss"] = d["l2_misses"] / sint
739716fd348SMartin Matuska        v["l2read"] = v["l2hits"] + v["l2miss"]
740*7a7741afSMartin Matuska        v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0
741716fd348SMartin Matuska
742716fd348SMartin Matuska        v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
743716fd348SMartin Matuska        v["l2asize"] = cur["l2_asize"]
744716fd348SMartin Matuska        v["l2size"] = cur["l2_size"]
745*7a7741afSMartin Matuska        v["l2bytes"] = d["l2_read_bytes"] / sint
746*7a7741afSMartin Matuska        v["l2wbytes"] = d["l2_write_bytes"] / sint
747716fd348SMartin Matuska
748716fd348SMartin Matuska        v["l2pref"] = cur["l2_prefetch_asize"]
749716fd348SMartin Matuska        v["l2mfu"] = cur["l2_mfu_asize"]
750716fd348SMartin Matuska        v["l2mru"] = cur["l2_mru_asize"]
751716fd348SMartin Matuska        v["l2data"] = cur["l2_bufc_data_asize"]
752716fd348SMartin Matuska        v["l2meta"] = cur["l2_bufc_metadata_asize"]
753*7a7741afSMartin Matuska        v["l2pref%"] = 100 * v["l2pref"] / v["l2asize"]
754*7a7741afSMartin Matuska        v["l2mfu%"] = 100 * v["l2mfu"] / v["l2asize"]
755*7a7741afSMartin Matuska        v["l2mru%"] = 100 * v["l2mru"] / v["l2asize"]
756*7a7741afSMartin Matuska        v["l2data%"] = 100 * v["l2data"] / v["l2asize"]
757*7a7741afSMartin Matuska        v["l2meta%"] = 100 * v["l2meta"] / v["l2asize"]
758716fd348SMartin Matuska
759716fd348SMartin Matuska    v["grow"] = 0 if cur["arc_no_grow"] else 1
760716fd348SMartin Matuska    v["need"] = cur["arc_need_free"]
761716fd348SMartin Matuska    v["free"] = cur["memory_free_bytes"]
762716fd348SMartin Matuska    v["avail"] = cur["memory_available_bytes"]
763716fd348SMartin Matuska    v["waste"] = cur["abd_chunk_waste_size"]
764716fd348SMartin Matuska
765716fd348SMartin Matuska
766716fd348SMartin Matuskadef main():
767716fd348SMartin Matuska    global sint
768716fd348SMartin Matuska    global count
769716fd348SMartin Matuska    global hdr_intr
770716fd348SMartin Matuska
771716fd348SMartin Matuska    i = 0
772716fd348SMartin Matuska    count_flag = 0
773716fd348SMartin Matuska
774716fd348SMartin Matuska    init()
775716fd348SMartin Matuska    if count > 0:
776716fd348SMartin Matuska        count_flag = 1
777716fd348SMartin Matuska
778716fd348SMartin Matuska    signal(SIGINT, SIG_DFL)
779716fd348SMartin Matuska    signal(SIGWINCH, resize_handler)
780716fd348SMartin Matuska    while True:
781716fd348SMartin Matuska        if i == 0:
782716fd348SMartin Matuska            print_header()
783716fd348SMartin Matuska
784716fd348SMartin Matuska        snap_stats()
785716fd348SMartin Matuska        calculate()
786716fd348SMartin Matuska        print_values()
787716fd348SMartin Matuska
788716fd348SMartin Matuska        if count_flag == 1:
789716fd348SMartin Matuska            if count <= 1:
790716fd348SMartin Matuska                break
791716fd348SMartin Matuska            count -= 1
792716fd348SMartin Matuska
793716fd348SMartin Matuska        i = 0 if i >= hdr_intr else i + 1
794716fd348SMartin Matuska        time.sleep(sint)
795716fd348SMartin Matuska
796716fd348SMartin Matuska    if out:
797716fd348SMartin Matuska        out.close()
798716fd348SMartin Matuska
799716fd348SMartin Matuska
800716fd348SMartin Matuskaif __name__ == '__main__':
801716fd348SMartin Matuska    main()
802