xref: /freebsd/sys/contrib/openzfs/cmd/arcstat.in (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1716fd348SMartin Matuska#!/usr/bin/env @PYTHON_SHEBANG@
2*61145dc2SMartin Matuska# SPDX-License-Identifier: CDDL-1.0
3716fd348SMartin Matuska#
4716fd348SMartin Matuska# Print out ZFS ARC Statistics exported via kstat(1)
5716fd348SMartin Matuska# For a definition of fields, or usage, use arcstat -v
6716fd348SMartin Matuska#
7716fd348SMartin Matuska# This script was originally a fork of the original arcstat.pl (0.1)
8716fd348SMartin Matuska# by Neelakanth Nadgir, originally published on his Sun blog on
9716fd348SMartin Matuska# 09/18/2007
10716fd348SMartin Matuska#     http://blogs.sun.com/realneel/entry/zfs_arc_statistics
11716fd348SMartin Matuska#
12716fd348SMartin Matuska# A new version aimed to improve upon the original by adding features
13716fd348SMartin Matuska# and fixing bugs as needed.  This version was maintained by Mike
14716fd348SMartin Matuska# Harsch and was hosted in a public open source repository:
15716fd348SMartin Matuska#    http://github.com/mharsch/arcstat
16716fd348SMartin Matuska#
17716fd348SMartin Matuska# but has since moved to the illumos-gate repository.
18716fd348SMartin Matuska#
19716fd348SMartin Matuska# This Python port was written by John Hixson for FreeNAS, introduced
20716fd348SMartin Matuska# in commit e2c29f:
21716fd348SMartin Matuska#    https://github.com/freenas/freenas
22716fd348SMartin Matuska#
23716fd348SMartin Matuska# and has been improved by many people since.
24716fd348SMartin Matuska#
25716fd348SMartin Matuska# CDDL HEADER START
26716fd348SMartin Matuska#
27716fd348SMartin Matuska# The contents of this file are subject to the terms of the
28716fd348SMartin Matuska# Common Development and Distribution License, Version 1.0 only
29716fd348SMartin Matuska# (the "License").  You may not use this file except in compliance
30716fd348SMartin Matuska# with the License.
31716fd348SMartin Matuska#
32716fd348SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
33271171e0SMartin Matuska# or https://opensource.org/licenses/CDDL-1.0.
34716fd348SMartin Matuska# See the License for the specific language governing permissions
35716fd348SMartin Matuska# and limitations under the License.
36716fd348SMartin Matuska#
37716fd348SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
38716fd348SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
39716fd348SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
40716fd348SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
41716fd348SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
42716fd348SMartin Matuska#
43716fd348SMartin Matuska# CDDL HEADER END
44716fd348SMartin Matuska#
45716fd348SMartin Matuska#
46716fd348SMartin Matuska# Fields have a fixed width. Every interval, we fill the "v"
47716fd348SMartin Matuska# hash with its corresponding value (v[field]=value) using calculate().
48716fd348SMartin Matuska# @hdr is the array of fields that needs to be printed, so we
49716fd348SMartin Matuska# just iterate over this array and print the values using our pretty printer.
50716fd348SMartin Matuska#
51716fd348SMartin Matuska# This script must remain compatible with Python 3.6+.
52716fd348SMartin Matuska#
53716fd348SMartin Matuska
54716fd348SMartin Matuskaimport sys
55716fd348SMartin Matuskaimport time
56716fd348SMartin Matuskaimport getopt
57716fd348SMartin Matuskaimport re
58716fd348SMartin Matuskaimport copy
59716fd348SMartin Matuska
60716fd348SMartin Matuskafrom signal import signal, SIGINT, SIGWINCH, SIG_DFL
61716fd348SMartin Matuska
62716fd348SMartin Matuska
63716fd348SMartin Matuskacols = {
64716fd348SMartin Matuska    # HDR:        [Size, Scale, Description]
65716fd348SMartin Matuska    "time":       [8, -1, "Time"],
6615f0b8c3SMartin Matuska    "hits":       [4, 1000, "ARC hits per second"],
6715f0b8c3SMartin Matuska    "iohs":       [4, 1000, "ARC I/O hits per second"],
68716fd348SMartin Matuska    "miss":       [4, 1000, "ARC misses per second"],
69716fd348SMartin Matuska    "read":       [4, 1000, "Total ARC accesses per second"],
70716fd348SMartin Matuska    "hit%":       [4, 100, "ARC hit percentage"],
7115f0b8c3SMartin Matuska    "ioh%":       [4, 100, "ARC I/O hit percentage"],
72716fd348SMartin Matuska    "miss%":      [5, 100, "ARC miss percentage"],
73716fd348SMartin Matuska    "dhit":       [4, 1000, "Demand hits per second"],
7415f0b8c3SMartin Matuska    "dioh":       [4, 1000, "Demand I/O hits per second"],
75716fd348SMartin Matuska    "dmis":       [4, 1000, "Demand misses per second"],
76716fd348SMartin Matuska    "dh%":        [3, 100, "Demand hit percentage"],
7715f0b8c3SMartin Matuska    "di%":        [3, 100, "Demand I/O hit percentage"],
78716fd348SMartin Matuska    "dm%":        [3, 100, "Demand miss percentage"],
7915f0b8c3SMartin Matuska    "ddhit":      [5, 1000, "Demand data hits per second"],
8015f0b8c3SMartin Matuska    "ddioh":      [5, 1000, "Demand data I/O hits per second"],
8115f0b8c3SMartin Matuska    "ddmis":      [5, 1000, "Demand data misses per second"],
8215f0b8c3SMartin Matuska    "ddh%":       [4, 100, "Demand data hit percentage"],
8315f0b8c3SMartin Matuska    "ddi%":       [4, 100, "Demand data I/O hit percentage"],
8415f0b8c3SMartin Matuska    "ddm%":       [4, 100, "Demand data miss percentage"],
8515f0b8c3SMartin Matuska    "dmhit":      [5, 1000, "Demand metadata hits per second"],
8615f0b8c3SMartin Matuska    "dmioh":      [5, 1000, "Demand metadata I/O hits per second"],
8715f0b8c3SMartin Matuska    "dmmis":      [5, 1000, "Demand metadata misses per second"],
8815f0b8c3SMartin Matuska    "dmh%":       [4, 100, "Demand metadata hit percentage"],
8915f0b8c3SMartin Matuska    "dmi%":       [4, 100, "Demand metadata I/O hit percentage"],
9015f0b8c3SMartin Matuska    "dmm%":       [4, 100, "Demand metadata miss percentage"],
91716fd348SMartin Matuska    "phit":       [4, 1000, "Prefetch hits per second"],
9215f0b8c3SMartin Matuska    "pioh":       [4, 1000, "Prefetch I/O hits per second"],
93716fd348SMartin Matuska    "pmis":       [4, 1000, "Prefetch misses per second"],
94716fd348SMartin Matuska    "ph%":        [3, 100, "Prefetch hits percentage"],
9515f0b8c3SMartin Matuska    "pi%":        [3, 100, "Prefetch I/O hits percentage"],
96716fd348SMartin Matuska    "pm%":        [3, 100, "Prefetch miss percentage"],
9715f0b8c3SMartin Matuska    "pdhit":      [5, 1000, "Prefetch data hits per second"],
9815f0b8c3SMartin Matuska    "pdioh":      [5, 1000, "Prefetch data I/O hits per second"],
9915f0b8c3SMartin Matuska    "pdmis":      [5, 1000, "Prefetch data misses per second"],
10015f0b8c3SMartin Matuska    "pdh%":       [4, 100, "Prefetch data hits percentage"],
10115f0b8c3SMartin Matuska    "pdi%":       [4, 100, "Prefetch data I/O hits percentage"],
10215f0b8c3SMartin Matuska    "pdm%":       [4, 100, "Prefetch data miss percentage"],
10315f0b8c3SMartin Matuska    "pmhit":      [5, 1000, "Prefetch metadata hits per second"],
10415f0b8c3SMartin Matuska    "pmioh":      [5, 1000, "Prefetch metadata I/O hits per second"],
10515f0b8c3SMartin Matuska    "pmmis":      [5, 1000, "Prefetch metadata misses per second"],
10615f0b8c3SMartin Matuska    "pmh%":       [4, 100, "Prefetch metadata hits percentage"],
10715f0b8c3SMartin Matuska    "pmi%":       [4, 100, "Prefetch metadata I/O hits percentage"],
10815f0b8c3SMartin Matuska    "pmm%":       [4, 100, "Prefetch metadata miss percentage"],
109716fd348SMartin Matuska    "mhit":       [4, 1000, "Metadata hits per second"],
11015f0b8c3SMartin Matuska    "mioh":       [4, 1000, "Metadata I/O hits per second"],
111716fd348SMartin Matuska    "mmis":       [4, 1000, "Metadata misses per second"],
112716fd348SMartin Matuska    "mread":      [5, 1000, "Metadata accesses per second"],
113716fd348SMartin Matuska    "mh%":        [3, 100, "Metadata hit percentage"],
11415f0b8c3SMartin Matuska    "mi%":        [3, 100, "Metadata I/O hit percentage"],
115716fd348SMartin Matuska    "mm%":        [3, 100, "Metadata miss percentage"],
116716fd348SMartin Matuska    "arcsz":      [5, 1024, "ARC size"],
11715f0b8c3SMartin Matuska    "size":       [5, 1024, "ARC size"],
11815f0b8c3SMartin Matuska    "c":          [5, 1024, "ARC target size"],
119716fd348SMartin Matuska    "mfu":        [4, 1000, "MFU list hits per second"],
120716fd348SMartin Matuska    "mru":        [4, 1000, "MRU list hits per second"],
121716fd348SMartin Matuska    "mfug":       [4, 1000, "MFU ghost list hits per second"],
122716fd348SMartin Matuska    "mrug":       [4, 1000, "MRU ghost list hits per second"],
12315f0b8c3SMartin Matuska    "unc":        [4, 1000, "Uncached list hits per second"],
124716fd348SMartin Matuska    "eskip":      [5, 1000, "evict_skip per second"],
125716fd348SMartin Matuska    "el2skip":    [7, 1000, "evict skip, due to l2 writes, per second"],
126716fd348SMartin Matuska    "el2cach":    [7, 1024, "Size of L2 cached evictions per second"],
127716fd348SMartin Matuska    "el2el":      [5, 1024, "Size of L2 eligible evictions per second"],
128716fd348SMartin Matuska    "el2mfu":     [6, 1024, "Size of L2 eligible MFU evictions per second"],
129716fd348SMartin Matuska    "el2mru":     [6, 1024, "Size of L2 eligible MRU evictions per second"],
130716fd348SMartin Matuska    "el2inel":    [7, 1024, "Size of L2 ineligible evictions per second"],
131716fd348SMartin Matuska    "mtxmis":     [6, 1000, "mutex_miss per second"],
132716fd348SMartin Matuska    "dread":      [5, 1000, "Demand accesses per second"],
13315f0b8c3SMartin Matuska    "ddread":     [6, 1000, "Demand data accesses per second"],
13415f0b8c3SMartin Matuska    "dmread":     [6, 1000, "Demand metadata accesses per second"],
135716fd348SMartin Matuska    "pread":      [5, 1000, "Prefetch accesses per second"],
13615f0b8c3SMartin Matuska    "pdread":     [6, 1000, "Prefetch data accesses per second"],
13715f0b8c3SMartin Matuska    "pmread":     [6, 1000, "Prefetch metadata accesses per second"],
138716fd348SMartin Matuska    "l2hits":     [6, 1000, "L2ARC hits per second"],
139716fd348SMartin Matuska    "l2miss":     [6, 1000, "L2ARC misses per second"],
140716fd348SMartin Matuska    "l2read":     [6, 1000, "Total L2ARC accesses per second"],
141716fd348SMartin Matuska    "l2hit%":     [6, 100, "L2ARC access hit percentage"],
142716fd348SMartin Matuska    "l2miss%":    [7, 100, "L2ARC access miss percentage"],
143716fd348SMartin Matuska    "l2pref":     [6, 1024, "L2ARC prefetch allocated size"],
144716fd348SMartin Matuska    "l2mfu":      [5, 1024, "L2ARC MFU allocated size"],
145716fd348SMartin Matuska    "l2mru":      [5, 1024, "L2ARC MRU allocated size"],
146716fd348SMartin Matuska    "l2data":     [6, 1024, "L2ARC data allocated size"],
147716fd348SMartin Matuska    "l2meta":     [6, 1024, "L2ARC metadata allocated size"],
148716fd348SMartin Matuska    "l2pref%":    [7, 100, "L2ARC prefetch percentage"],
149716fd348SMartin Matuska    "l2mfu%":     [6, 100, "L2ARC MFU percentage"],
150716fd348SMartin Matuska    "l2mru%":     [6, 100, "L2ARC MRU percentage"],
151716fd348SMartin Matuska    "l2data%":    [7, 100, "L2ARC data percentage"],
152716fd348SMartin Matuska    "l2meta%":    [7, 100, "L2ARC metadata percentage"],
153716fd348SMartin Matuska    "l2asize":    [7, 1024, "Actual (compressed) size of the L2ARC"],
154716fd348SMartin Matuska    "l2size":     [6, 1024, "Size of the L2ARC"],
155716fd348SMartin Matuska    "l2bytes":    [7, 1024, "Bytes read per second from the L2ARC"],
1567a7741afSMartin Matuska    "l2wbytes":   [8, 1024, "Bytes written per second to the L2ARC"],
157716fd348SMartin Matuska    "grow":       [4, 1000, "ARC grow disabled"],
15815f0b8c3SMartin Matuska    "need":       [5, 1024, "ARC reclaim need"],
15915f0b8c3SMartin Matuska    "free":       [5, 1024, "ARC free memory"],
160716fd348SMartin Matuska    "avail":      [5, 1024, "ARC available memory"],
161716fd348SMartin Matuska    "waste":      [5, 1024, "Wasted memory due to round up to pagesize"],
1620d4ad640SMartin Matuska    "ztotal":     [6, 1000, "zfetch total prefetcher calls per second"],
1630d4ad640SMartin Matuska    "zhits":      [5, 1000, "zfetch stream hits per second"],
1640d4ad640SMartin Matuska    "zahead":     [6, 1000, "zfetch hits ahead of streams per second"],
1650d4ad640SMartin Matuska    "zpast":      [5, 1000, "zfetch hits behind streams per second"],
1660d4ad640SMartin Matuska    "zmisses":    [7, 1000, "zfetch stream misses per second"],
1670d4ad640SMartin Matuska    "zmax":       [4, 1000, "zfetch limit reached per second"],
1680d4ad640SMartin Matuska    "zfuture":    [7, 1000, "zfetch stream future per second"],
1690d4ad640SMartin Matuska    "zstride":    [7, 1000, "zfetch stream strides per second"],
1700d4ad640SMartin Matuska    "zissued":    [7, 1000, "zfetch prefetches issued per second"],
1710d4ad640SMartin Matuska    "zactive":    [7, 1000, "zfetch prefetches active per second"],
172716fd348SMartin Matuska}
173716fd348SMartin Matuska
1747a7741afSMartin Matuska# ARC structural breakdown from arc_summary
1757a7741afSMartin Matuskastructfields = {
1767a7741afSMartin Matuska    "cmp":      ["compressed", "Compressed"],
1777a7741afSMartin Matuska    "ovh":      ["overhead", "Overhead"],
1787a7741afSMartin Matuska    "bon":      ["bonus", "Bonus"],
1797a7741afSMartin Matuska    "dno":      ["dnode", "Dnode"],
1807a7741afSMartin Matuska    "dbu":      ["dbuf", "Dbuf"],
1817a7741afSMartin Matuska    "hdr":      ["hdr", "Header"],
1827a7741afSMartin Matuska    "l2h":      ["l2_hdr", "L2 header"],
1837a7741afSMartin Matuska    "abd":      ["abd_chunk_waste", "ABD chunk waste"],
1847a7741afSMartin Matuska}
1857a7741afSMartin Matuskastructstats = {                             # size stats
1867a7741afSMartin Matuska    "percent":  "size",                     # percentage of this value
1877a7741afSMartin Matuska    "sz":       ["_size", "size"],
1887a7741afSMartin Matuska}
1897a7741afSMartin Matuska
1907a7741afSMartin Matuska# ARC types breakdown from arc_summary
1917a7741afSMartin Matuskatypefields = {
1927a7741afSMartin Matuska    "data":     ["data", "ARC data"],
1937a7741afSMartin Matuska    "meta":     ["metadata", "ARC metadata"],
1947a7741afSMartin Matuska}
1957a7741afSMartin Matuskatypestats = {                               # size stats
1967a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
1977a7741afSMartin Matuska    "tg":       ["_target", "target"],
1987a7741afSMartin Matuska    "sz":       ["_size", "size"],
1997a7741afSMartin Matuska}
2007a7741afSMartin Matuska
2017a7741afSMartin Matuska# ARC states breakdown from arc_summary
2027a7741afSMartin Matuskastatefields = {
2037a7741afSMartin Matuska    "ano":      ["anon", "Anonymous"],
2047a7741afSMartin Matuska    "mfu":      ["mfu", "MFU"],
2057a7741afSMartin Matuska    "mru":      ["mru", "MRU"],
2067a7741afSMartin Matuska    "unc":      ["uncached", "Uncached"],
2077a7741afSMartin Matuska}
2087a7741afSMartin Matuskatargetstats = {
2097a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
2107a7741afSMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
2117a7741afSMartin Matuska    "tg":       ["_target", "target"],
2127a7741afSMartin Matuska    "dt":       ["_data_target", "data target"],
2137a7741afSMartin Matuska    "mt":       ["_metadata_target", "metadata target"],
2147a7741afSMartin Matuska}
2157a7741afSMartin Matuskastatestats = {                              # size stats
2167a7741afSMartin Matuska    "percent":  "cachessz",                 # percentage of this value
2177a7741afSMartin Matuska    "sz":       ["_size", "size"],
2187a7741afSMartin Matuska    "da":       ["_data", "data size"],
2197a7741afSMartin Matuska    "me":       ["_metadata", "metadata size"],
2207a7741afSMartin Matuska    "ed":       ["_evictable_data", "evictable data size"],
2217a7741afSMartin Matuska    "em":       ["_evictable_metadata", "evictable metadata size"],
2227a7741afSMartin Matuska}
2237a7741afSMartin Matuskaghoststats = {
2247a7741afSMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
2257a7741afSMartin Matuska    "gsz":      ["_ghost_size", "ghost size"],
2267a7741afSMartin Matuska    "gd":       ["_ghost_data", "ghost data size"],
2277a7741afSMartin Matuska    "gm":       ["_ghost_metadata", "ghost metadata size"],
2287a7741afSMartin Matuska}
2297a7741afSMartin Matuska
2307a7741afSMartin Matuska# fields and stats
2317a7741afSMartin Matuskafieldstats = [
2327a7741afSMartin Matuska    [structfields, structstats],
2337a7741afSMartin Matuska    [typefields, typestats],
2347a7741afSMartin Matuska    [statefields, targetstats, statestats, ghoststats],
2357a7741afSMartin Matuska]
2367a7741afSMartin Matuskafor fs in fieldstats:
2377a7741afSMartin Matuska    fields, stats = fs[0], fs[1:]
2387a7741afSMartin Matuska    for field, fieldval in fields.items():
2397a7741afSMartin Matuska        for group in stats:
2407a7741afSMartin Matuska            for stat, statval in group.items():
2417a7741afSMartin Matuska                if stat in ["fields", "percent"] or \
2427a7741afSMartin Matuska                    ("fields" in group and field not in group["fields"]):
2437a7741afSMartin Matuska                    continue
2447a7741afSMartin Matuska                colname = field + stat
2457a7741afSMartin Matuska                coldesc = fieldval[1] + " " + statval[1]
2467a7741afSMartin Matuska                cols[colname] = [len(colname), 1024, coldesc]
2477a7741afSMartin Matuska                if "percent" in group:
2487a7741afSMartin Matuska                    cols[colname + "%"] = [len(colname) + 1, 100, \
2497a7741afSMartin Matuska                        coldesc + " percentage"]
2507a7741afSMartin Matuska
251716fd348SMartin Matuskav = {}
25215f0b8c3SMartin Matuskahdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%",
25315f0b8c3SMartin Matuska       "size", "c", "avail"]
25415f0b8c3SMartin Matuskaxhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis",
25515f0b8c3SMartin Matuska        "dread", "pread", "read"]
2560d4ad640SMartin Matuskazhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax",
2570d4ad640SMartin Matuska        "zfuture", "zstride", "zissued", "zactive"]
258716fd348SMartin Matuskasint = 1               # Default interval is 1 second
259716fd348SMartin Matuskacount = 1              # Default count is 1
260716fd348SMartin Matuskahdr_intr = 20          # Print header every 20 lines of output
261716fd348SMartin Matuskaopfile = None
262716fd348SMartin Matuskasep = "  "              # Default separator is 2 spaces
263716fd348SMartin Matuskal2exist = False
264716fd348SMartin Matuskacmd = ("Usage: arcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
265716fd348SMartin Matuska       "[count]]\n")
266716fd348SMartin Matuskacur = {}
267716fd348SMartin Matuskad = {}
268716fd348SMartin Matuskaout = None
269716fd348SMartin Matuskakstat = None
270716fd348SMartin Matuskapretty_print = True
271716fd348SMartin Matuska
272716fd348SMartin Matuska
273716fd348SMartin Matuskaif sys.platform.startswith('freebsd'):
274716fd348SMartin Matuska    # Requires py-sysctl on FreeBSD
275716fd348SMartin Matuska    import sysctl
276716fd348SMartin Matuska
277716fd348SMartin Matuska    def kstat_update():
278716fd348SMartin Matuska        global kstat
279716fd348SMartin Matuska
280716fd348SMartin Matuska        k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats')
281716fd348SMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
282b985c9caSMartin Matuska        k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats')
283b985c9caSMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
284716fd348SMartin Matuska
285716fd348SMartin Matuska        if not k:
286716fd348SMartin Matuska            sys.exit(1)
287716fd348SMartin Matuska
288716fd348SMartin Matuska        kstat = {}
289716fd348SMartin Matuska
290716fd348SMartin Matuska        for s in k:
291716fd348SMartin Matuska            if not s:
292716fd348SMartin Matuska                continue
293716fd348SMartin Matuska
294716fd348SMartin Matuska            name, value = s.name, s.value
295b985c9caSMartin Matuska
296b985c9caSMartin Matuska            if "arcstats" in name:
297716fd348SMartin Matuska                # Trims 'kstat.zfs.misc.arcstats' from the name
298716fd348SMartin Matuska                kstat[name[24:]] = int(value)
299b985c9caSMartin Matuska            else:
300b985c9caSMartin Matuska                kstat["zfetch_" + name[27:]] = int(value)
301716fd348SMartin Matuska
302716fd348SMartin Matuskaelif sys.platform.startswith('linux'):
303716fd348SMartin Matuska    def kstat_update():
304716fd348SMartin Matuska        global kstat
305716fd348SMartin Matuska
3060d4ad640SMartin Matuska        k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
307716fd348SMartin Matuska
3080d4ad640SMartin Matuska        k2 = ["zfetch_" + line.strip() for line in
3090d4ad640SMartin Matuska             open('/proc/spl/kstat/zfs/zfetchstats')]
3100d4ad640SMartin Matuska
3110d4ad640SMartin Matuska        if k1 is None or k2 is None:
312716fd348SMartin Matuska            sys.exit(1)
313716fd348SMartin Matuska
3140d4ad640SMartin Matuska        del k1[0:2]
3150d4ad640SMartin Matuska        del k2[0:2]
3160d4ad640SMartin Matuska        k = k1 + k2
317716fd348SMartin Matuska        kstat = {}
318716fd348SMartin Matuska
319716fd348SMartin Matuska        for s in k:
320716fd348SMartin Matuska            if not s:
321716fd348SMartin Matuska                continue
322716fd348SMartin Matuska
323716fd348SMartin Matuska            name, unused, value = s.split()
324716fd348SMartin Matuska            kstat[name] = int(value)
325716fd348SMartin Matuska
326716fd348SMartin Matuska
327716fd348SMartin Matuskadef detailed_usage():
328716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
329716fd348SMartin Matuska    sys.stderr.write("Field definitions are as follows:\n")
330716fd348SMartin Matuska    for key in cols:
331716fd348SMartin Matuska        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
332716fd348SMartin Matuska    sys.stderr.write("\n")
333716fd348SMartin Matuska
334716fd348SMartin Matuska    sys.exit(0)
335716fd348SMartin Matuska
336716fd348SMartin Matuska
337716fd348SMartin Matuskadef usage():
338716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
339716fd348SMartin Matuska    sys.stderr.write("\t -h : Print this help message\n")
340716fd348SMartin Matuska    sys.stderr.write("\t -a : Print all possible stats\n")
341716fd348SMartin Matuska    sys.stderr.write("\t -v : List all possible field headers and definitions"
342716fd348SMartin Matuska                     "\n")
343716fd348SMartin Matuska    sys.stderr.write("\t -x : Print extended stats\n")
3440d4ad640SMartin Matuska    sys.stderr.write("\t -z : Print zfetch stats\n")
345716fd348SMartin Matuska    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
346716fd348SMartin Matuska    sys.stderr.write("\t -o : Redirect output to the specified file\n")
347716fd348SMartin Matuska    sys.stderr.write("\t -s : Override default field separator with custom "
348716fd348SMartin Matuska                     "character or string\n")
349716fd348SMartin Matuska    sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n")
350716fd348SMartin Matuska    sys.stderr.write("\nExamples:\n")
351716fd348SMartin Matuska    sys.stderr.write("\tarcstat -o /tmp/a.log 2 10\n")
352716fd348SMartin Matuska    sys.stderr.write("\tarcstat -s \",\" -o /tmp/a.log 2 10\n")
353716fd348SMartin Matuska    sys.stderr.write("\tarcstat -v\n")
354716fd348SMartin Matuska    sys.stderr.write("\tarcstat -f time,hit%,dh%,ph%,mh% 1\n")
355716fd348SMartin Matuska    sys.stderr.write("\n")
356716fd348SMartin Matuska
357716fd348SMartin Matuska    sys.exit(1)
358716fd348SMartin Matuska
359716fd348SMartin Matuska
360716fd348SMartin Matuskadef snap_stats():
361716fd348SMartin Matuska    global cur
362716fd348SMartin Matuska    global kstat
363716fd348SMartin Matuska
364716fd348SMartin Matuska    prev = copy.deepcopy(cur)
365716fd348SMartin Matuska    kstat_update()
366716fd348SMartin Matuska
367716fd348SMartin Matuska    cur = kstat
3687a7741afSMartin Matuska
3697a7741afSMartin Matuska    # fill in additional values from arc_summary
3707a7741afSMartin Matuska    cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\
3717a7741afSMartin Matuska        cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\
3727a7741afSMartin Matuska        cur["uncached_data"]+cur["uncached_metadata"]
3737a7741afSMartin Matuska    s = 4294967296
3747a7741afSMartin Matuska    pd = cur["pd"]
3757a7741afSMartin Matuska    pm = cur["pm"]
3767a7741afSMartin Matuska    meta = cur["meta"]
3777a7741afSMartin Matuska    v = (s-int(pd))*(s-int(meta))/s
3787a7741afSMartin Matuska    cur["mfu_data_target"] = v / 65536 * caches_size / 65536
3797a7741afSMartin Matuska    v = (s-int(pm))*int(meta)/s
3807a7741afSMartin Matuska    cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536
3817a7741afSMartin Matuska    v = int(pd)*(s-int(meta))/s
3827a7741afSMartin Matuska    cur["mru_data_target"] = v / 65536 * caches_size / 65536
3837a7741afSMartin Matuska    v = int(pm)*int(meta)/s
3847a7741afSMartin Matuska    cur["mru_metadata_target"] = v / 65536 * caches_size / 65536
3857a7741afSMartin Matuska
3867a7741afSMartin Matuska    cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"]
3877a7741afSMartin Matuska    cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"]
3887a7741afSMartin Matuska    cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"]
3897a7741afSMartin Matuska    cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"]
3907a7741afSMartin Matuska
391716fd348SMartin Matuska    for key in cur:
392716fd348SMartin Matuska        if re.match(key, "class"):
393716fd348SMartin Matuska            continue
394716fd348SMartin Matuska        if key in prev:
395716fd348SMartin Matuska            d[key] = cur[key] - prev[key]
396716fd348SMartin Matuska        else:
397716fd348SMartin Matuska            d[key] = cur[key]
398716fd348SMartin Matuska
399716fd348SMartin Matuska
4007a7741afSMartin Matuskadef isint(num):
4017a7741afSMartin Matuska    if isinstance(num, float):
4027a7741afSMartin Matuska        return num.is_integer()
4037a7741afSMartin Matuska    if isinstance(num, int):
4047a7741afSMartin Matuska        return True
4057a7741afSMartin Matuska    return False
4067a7741afSMartin Matuska
4077a7741afSMartin Matuska
408716fd348SMartin Matuskadef prettynum(sz, scale, num=0):
409716fd348SMartin Matuska    suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
410716fd348SMartin Matuska    index = 0
411716fd348SMartin Matuska
412716fd348SMartin Matuska    # Special case for date field
413716fd348SMartin Matuska    if scale == -1:
414716fd348SMartin Matuska        return "%s" % num
415716fd348SMartin Matuska
4167a7741afSMartin Matuska    if scale != 100:
417716fd348SMartin Matuska        while abs(num) > scale and index < 5:
418716fd348SMartin Matuska            num = num / scale
419716fd348SMartin Matuska            index += 1
420716fd348SMartin Matuska
4217a7741afSMartin Matuska    width = sz - (0 if index == 0 else 1)
4227a7741afSMartin Matuska    intlen = len("%.0f" % num)              # %.0f rounds to nearest int
4237a7741afSMartin Matuska    if sint == 1 and isint(num) or width < intlen + 2:
4247a7741afSMartin Matuska        decimal = 0
425716fd348SMartin Matuska    else:
4267a7741afSMartin Matuska        decimal = 1
4277a7741afSMartin Matuska    return "%*.*f%s" % (width, decimal, num, suffix[index])
428716fd348SMartin Matuska
429716fd348SMartin Matuska
430716fd348SMartin Matuskadef print_values():
431716fd348SMartin Matuska    global hdr
432716fd348SMartin Matuska    global sep
433716fd348SMartin Matuska    global v
434716fd348SMartin Matuska    global pretty_print
435716fd348SMartin Matuska
436716fd348SMartin Matuska    if pretty_print:
437716fd348SMartin Matuska        fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
438716fd348SMartin Matuska    else:
43908aba0aeSMartin Matuska        fmt = lambda col: str(v[col])
440716fd348SMartin Matuska
441716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
442716fd348SMartin Matuska    sys.stdout.write("\n")
443716fd348SMartin Matuska    sys.stdout.flush()
444716fd348SMartin Matuska
445716fd348SMartin Matuska
446716fd348SMartin Matuskadef print_header():
447716fd348SMartin Matuska    global hdr
448716fd348SMartin Matuska    global sep
449716fd348SMartin Matuska    global pretty_print
450716fd348SMartin Matuska
451716fd348SMartin Matuska    if pretty_print:
452716fd348SMartin Matuska        fmt = lambda col: "%*s" % (cols[col][0], col)
453716fd348SMartin Matuska    else:
454716fd348SMartin Matuska        fmt = lambda col: col
455716fd348SMartin Matuska
456716fd348SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
457716fd348SMartin Matuska    sys.stdout.write("\n")
458716fd348SMartin Matuska
459716fd348SMartin Matuska
460716fd348SMartin Matuskadef get_terminal_lines():
461716fd348SMartin Matuska    try:
462716fd348SMartin Matuska        import fcntl
463716fd348SMartin Matuska        import termios
464716fd348SMartin Matuska        import struct
465716fd348SMartin Matuska        data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
466716fd348SMartin Matuska        sz = struct.unpack('hh', data)
467716fd348SMartin Matuska        return sz[0]
468716fd348SMartin Matuska    except Exception:
469716fd348SMartin Matuska        pass
470716fd348SMartin Matuska
471716fd348SMartin Matuska
472716fd348SMartin Matuskadef update_hdr_intr():
473716fd348SMartin Matuska    global hdr_intr
474716fd348SMartin Matuska
475716fd348SMartin Matuska    lines = get_terminal_lines()
476716fd348SMartin Matuska    if lines and lines > 3:
477716fd348SMartin Matuska        hdr_intr = lines - 3
478716fd348SMartin Matuska
479716fd348SMartin Matuska
480716fd348SMartin Matuskadef resize_handler(signum, frame):
481716fd348SMartin Matuska    update_hdr_intr()
482716fd348SMartin Matuska
483716fd348SMartin Matuska
484716fd348SMartin Matuskadef init():
485716fd348SMartin Matuska    global sint
486716fd348SMartin Matuska    global count
487716fd348SMartin Matuska    global hdr
488716fd348SMartin Matuska    global xhdr
4890d4ad640SMartin Matuska    global zhdr
490716fd348SMartin Matuska    global opfile
491716fd348SMartin Matuska    global sep
492716fd348SMartin Matuska    global out
493716fd348SMartin Matuska    global l2exist
494716fd348SMartin Matuska    global pretty_print
495716fd348SMartin Matuska
496716fd348SMartin Matuska    desired_cols = None
497716fd348SMartin Matuska    aflag = False
498716fd348SMartin Matuska    xflag = False
499716fd348SMartin Matuska    hflag = False
500716fd348SMartin Matuska    vflag = False
5010d4ad640SMartin Matuska    zflag = False
502716fd348SMartin Matuska    i = 1
503716fd348SMartin Matuska
504716fd348SMartin Matuska    try:
505716fd348SMartin Matuska        opts, args = getopt.getopt(
506716fd348SMartin Matuska            sys.argv[1:],
5070d4ad640SMartin Matuska            "axzo:hvs:f:p",
508716fd348SMartin Matuska            [
509716fd348SMartin Matuska                "all",
510716fd348SMartin Matuska                "extended",
5110d4ad640SMartin Matuska                "zfetch",
512716fd348SMartin Matuska                "outfile",
513716fd348SMartin Matuska                "help",
514716fd348SMartin Matuska                "verbose",
515716fd348SMartin Matuska                "separator",
516716fd348SMartin Matuska                "columns",
517716fd348SMartin Matuska                "parsable"
518716fd348SMartin Matuska            ]
519716fd348SMartin Matuska        )
520716fd348SMartin Matuska    except getopt.error as msg:
521716fd348SMartin Matuska        sys.stderr.write("Error: %s\n" % str(msg))
522716fd348SMartin Matuska        usage()
523716fd348SMartin Matuska        opts = None
524716fd348SMartin Matuska
525716fd348SMartin Matuska    for opt, arg in opts:
526716fd348SMartin Matuska        if opt in ('-a', '--all'):
527716fd348SMartin Matuska            aflag = True
528716fd348SMartin Matuska        if opt in ('-x', '--extended'):
529716fd348SMartin Matuska            xflag = True
530716fd348SMartin Matuska        if opt in ('-o', '--outfile'):
531716fd348SMartin Matuska            opfile = arg
532716fd348SMartin Matuska            i += 1
533716fd348SMartin Matuska        if opt in ('-h', '--help'):
534716fd348SMartin Matuska            hflag = True
535716fd348SMartin Matuska        if opt in ('-v', '--verbose'):
536716fd348SMartin Matuska            vflag = True
537716fd348SMartin Matuska        if opt in ('-s', '--separator'):
538716fd348SMartin Matuska            sep = arg
539716fd348SMartin Matuska            i += 1
540716fd348SMartin Matuska        if opt in ('-f', '--columns'):
541716fd348SMartin Matuska            desired_cols = arg
542716fd348SMartin Matuska            i += 1
543716fd348SMartin Matuska        if opt in ('-p', '--parsable'):
544716fd348SMartin Matuska            pretty_print = False
5450d4ad640SMartin Matuska        if opt in ('-z', '--zfetch'):
5460d4ad640SMartin Matuska            zflag = True
547716fd348SMartin Matuska        i += 1
548716fd348SMartin Matuska
549716fd348SMartin Matuska    argv = sys.argv[i:]
550716fd348SMartin Matuska    sint = int(argv[0]) if argv else sint
551716fd348SMartin Matuska    count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1)
552716fd348SMartin Matuska
5530d4ad640SMartin Matuska    if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols):
554716fd348SMartin Matuska        usage()
555716fd348SMartin Matuska
556716fd348SMartin Matuska    if vflag:
557716fd348SMartin Matuska        detailed_usage()
558716fd348SMartin Matuska
559716fd348SMartin Matuska    if xflag:
560716fd348SMartin Matuska        hdr = xhdr
561716fd348SMartin Matuska
5620d4ad640SMartin Matuska    if zflag:
5630d4ad640SMartin Matuska        hdr = zhdr
5640d4ad640SMartin Matuska
565716fd348SMartin Matuska    update_hdr_intr()
566716fd348SMartin Matuska
567716fd348SMartin Matuska    # check if L2ARC exists
568716fd348SMartin Matuska    snap_stats()
569716fd348SMartin Matuska    l2_size = cur.get("l2_size")
570716fd348SMartin Matuska    if l2_size:
571716fd348SMartin Matuska        l2exist = True
572716fd348SMartin Matuska
573716fd348SMartin Matuska    if desired_cols:
574716fd348SMartin Matuska        hdr = desired_cols.split(",")
575716fd348SMartin Matuska
576716fd348SMartin Matuska        invalid = []
577716fd348SMartin Matuska        incompat = []
578716fd348SMartin Matuska        for ele in hdr:
579716fd348SMartin Matuska            if ele not in cols:
580716fd348SMartin Matuska                invalid.append(ele)
581716fd348SMartin Matuska            elif not l2exist and ele.startswith("l2"):
582716fd348SMartin Matuska                sys.stdout.write("No L2ARC Here\n%s\n" % ele)
583716fd348SMartin Matuska                incompat.append(ele)
584716fd348SMartin Matuska
585716fd348SMartin Matuska        if len(invalid) > 0:
586716fd348SMartin Matuska            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
587716fd348SMartin Matuska            usage()
588716fd348SMartin Matuska
589716fd348SMartin Matuska        if len(incompat) > 0:
590716fd348SMartin Matuska            sys.stderr.write("Incompatible field specified! -- %s\n" %
591716fd348SMartin Matuska                             incompat)
592716fd348SMartin Matuska            usage()
593716fd348SMartin Matuska
594716fd348SMartin Matuska    if aflag:
595716fd348SMartin Matuska        if l2exist:
596716fd348SMartin Matuska            hdr = cols.keys()
597716fd348SMartin Matuska        else:
598716fd348SMartin Matuska            hdr = [col for col in cols.keys() if not col.startswith("l2")]
599716fd348SMartin Matuska
600716fd348SMartin Matuska    if opfile:
601716fd348SMartin Matuska        try:
602716fd348SMartin Matuska            out = open(opfile, "w")
603716fd348SMartin Matuska            sys.stdout = out
604716fd348SMartin Matuska
605716fd348SMartin Matuska        except IOError:
606716fd348SMartin Matuska            sys.stderr.write("Cannot open %s for writing\n" % opfile)
607716fd348SMartin Matuska            sys.exit(1)
608716fd348SMartin Matuska
609716fd348SMartin Matuska
610716fd348SMartin Matuskadef calculate():
611716fd348SMartin Matuska    global d
612716fd348SMartin Matuska    global v
613716fd348SMartin Matuska    global l2exist
614716fd348SMartin Matuska
615716fd348SMartin Matuska    v = dict()
616716fd348SMartin Matuska    v["time"] = time.strftime("%H:%M:%S", time.localtime())
6177a7741afSMartin Matuska    v["hits"] = d["hits"] / sint
6187a7741afSMartin Matuska    v["iohs"] = d["iohits"] / sint
6197a7741afSMartin Matuska    v["miss"] = d["misses"] / sint
62015f0b8c3SMartin Matuska    v["read"] = v["hits"] + v["iohs"] + v["miss"]
6217a7741afSMartin Matuska    v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0
6227a7741afSMartin Matuska    v["ioh%"] = 100 * v["iohs"] / v["read"] if v["read"] > 0 else 0
62315f0b8c3SMartin Matuska    v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0
624716fd348SMartin Matuska
6257a7741afSMartin Matuska    v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint
6267a7741afSMartin Matuska    v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) / sint
6277a7741afSMartin Matuska    v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
628716fd348SMartin Matuska
62915f0b8c3SMartin Matuska    v["dread"] = v["dhit"] + v["dioh"] + v["dmis"]
6307a7741afSMartin Matuska    v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0
6317a7741afSMartin Matuska    v["di%"] = 100 * v["dioh"] / v["dread"] if v["dread"] > 0 else 0
63215f0b8c3SMartin Matuska    v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0
63315f0b8c3SMartin Matuska
6347a7741afSMartin Matuska    v["ddhit"] = d["demand_data_hits"] / sint
6357a7741afSMartin Matuska    v["ddioh"] = d["demand_data_iohits"] / sint
6367a7741afSMartin Matuska    v["ddmis"] = d["demand_data_misses"] / sint
63715f0b8c3SMartin Matuska
63815f0b8c3SMartin Matuska    v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"]
6397a7741afSMartin Matuska    v["ddh%"] = 100 * v["ddhit"] / v["ddread"] if v["ddread"] > 0 else 0
6407a7741afSMartin Matuska    v["ddi%"] = 100 * v["ddioh"] / v["ddread"] if v["ddread"] > 0 else 0
64115f0b8c3SMartin Matuska    v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0
64215f0b8c3SMartin Matuska
6437a7741afSMartin Matuska    v["dmhit"] = d["demand_metadata_hits"] / sint
6447a7741afSMartin Matuska    v["dmioh"] = d["demand_metadata_iohits"] / sint
6457a7741afSMartin Matuska    v["dmmis"] = d["demand_metadata_misses"] / sint
64615f0b8c3SMartin Matuska
64715f0b8c3SMartin Matuska    v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"]
6487a7741afSMartin Matuska    v["dmh%"] = 100 * v["dmhit"] / v["dmread"] if v["dmread"] > 0 else 0
6497a7741afSMartin Matuska    v["dmi%"] = 100 * v["dmioh"] / v["dmread"] if v["dmread"] > 0 else 0
65015f0b8c3SMartin Matuska    v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0
651716fd348SMartin Matuska
6527a7741afSMartin Matuska    v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
65315f0b8c3SMartin Matuska    v["pioh"] = (d["prefetch_data_iohits"] +
6547a7741afSMartin Matuska                 d["prefetch_metadata_iohits"]) / sint
655716fd348SMartin Matuska    v["pmis"] = (d["prefetch_data_misses"] +
6567a7741afSMartin Matuska                 d["prefetch_metadata_misses"]) / sint
657716fd348SMartin Matuska
65815f0b8c3SMartin Matuska    v["pread"] = v["phit"] + v["pioh"] + v["pmis"]
6597a7741afSMartin Matuska    v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0
6607a7741afSMartin Matuska    v["pi%"] = 100 * v["pioh"] / v["pread"] if v["pread"] > 0 else 0
66115f0b8c3SMartin Matuska    v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0
66215f0b8c3SMartin Matuska
6637a7741afSMartin Matuska    v["pdhit"] = d["prefetch_data_hits"] / sint
6647a7741afSMartin Matuska    v["pdioh"] = d["prefetch_data_iohits"] / sint
6657a7741afSMartin Matuska    v["pdmis"] = d["prefetch_data_misses"] / sint
66615f0b8c3SMartin Matuska
66715f0b8c3SMartin Matuska    v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"]
6687a7741afSMartin Matuska    v["pdh%"] = 100 * v["pdhit"] / v["pdread"] if v["pdread"] > 0 else 0
6697a7741afSMartin Matuska    v["pdi%"] = 100 * v["pdioh"] / v["pdread"] if v["pdread"] > 0 else 0
67015f0b8c3SMartin Matuska    v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0
67115f0b8c3SMartin Matuska
6727a7741afSMartin Matuska    v["pmhit"] = d["prefetch_metadata_hits"] / sint
6737a7741afSMartin Matuska    v["pmioh"] = d["prefetch_metadata_iohits"] / sint
6747a7741afSMartin Matuska    v["pmmis"] = d["prefetch_metadata_misses"] / sint
67515f0b8c3SMartin Matuska
67615f0b8c3SMartin Matuska    v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"]
6777a7741afSMartin Matuska    v["pmh%"] = 100 * v["pmhit"] / v["pmread"] if v["pmread"] > 0 else 0
6787a7741afSMartin Matuska    v["pmi%"] = 100 * v["pmioh"] / v["pmread"] if v["pmread"] > 0 else 0
67915f0b8c3SMartin Matuska    v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0
680716fd348SMartin Matuska
681716fd348SMartin Matuska    v["mhit"] = (d["prefetch_metadata_hits"] +
6827a7741afSMartin Matuska                 d["demand_metadata_hits"]) / sint
68315f0b8c3SMartin Matuska    v["mioh"] = (d["prefetch_metadata_iohits"] +
6847a7741afSMartin Matuska                 d["demand_metadata_iohits"]) / sint
685716fd348SMartin Matuska    v["mmis"] = (d["prefetch_metadata_misses"] +
6867a7741afSMartin Matuska                 d["demand_metadata_misses"]) / sint
687716fd348SMartin Matuska
68815f0b8c3SMartin Matuska    v["mread"] = v["mhit"] + v["mioh"] + v["mmis"]
6897a7741afSMartin Matuska    v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0
6907a7741afSMartin Matuska    v["mi%"] = 100 * v["mioh"] / v["mread"] if v["mread"] > 0 else 0
69115f0b8c3SMartin Matuska    v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0
692716fd348SMartin Matuska
693716fd348SMartin Matuska    v["arcsz"] = cur["size"]
694716fd348SMartin Matuska    v["size"] = cur["size"]
695716fd348SMartin Matuska    v["c"] = cur["c"]
6967a7741afSMartin Matuska    v["mfu"] = d["mfu_hits"] / sint
6977a7741afSMartin Matuska    v["mru"] = d["mru_hits"] / sint
6987a7741afSMartin Matuska    v["mrug"] = d["mru_ghost_hits"] / sint
6997a7741afSMartin Matuska    v["mfug"] = d["mfu_ghost_hits"] / sint
7007a7741afSMartin Matuska    v["unc"] = d["uncached_hits"] / sint
7017a7741afSMartin Matuska    v["eskip"] = d["evict_skip"] / sint
7027a7741afSMartin Matuska    v["el2skip"] = d["evict_l2_skip"] / sint
7037a7741afSMartin Matuska    v["el2cach"] = d["evict_l2_cached"] / sint
7047a7741afSMartin Matuska    v["el2el"] = d["evict_l2_eligible"] / sint
7057a7741afSMartin Matuska    v["el2mfu"] = d["evict_l2_eligible_mfu"] / sint
7067a7741afSMartin Matuska    v["el2mru"] = d["evict_l2_eligible_mru"] / sint
7077a7741afSMartin Matuska    v["el2inel"] = d["evict_l2_ineligible"] / sint
7087a7741afSMartin Matuska    v["mtxmis"] = d["mutex_miss"] / sint
7090d4ad640SMartin Matuska    v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] +
7107a7741afSMartin Matuska                   d["zfetch_past"] + d["zfetch_misses"]) / sint
7117a7741afSMartin Matuska    v["zhits"] = d["zfetch_hits"] / sint
7127a7741afSMartin Matuska    v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) / sint
7137a7741afSMartin Matuska    v["zpast"] = d["zfetch_past"] / sint
7147a7741afSMartin Matuska    v["zmisses"] = d["zfetch_misses"] / sint
7157a7741afSMartin Matuska    v["zmax"] = d["zfetch_max_streams"] / sint
7167a7741afSMartin Matuska    v["zfuture"] = d["zfetch_future"] / sint
7177a7741afSMartin Matuska    v["zstride"] = d["zfetch_stride"] / sint
7187a7741afSMartin Matuska    v["zissued"] = d["zfetch_io_issued"] / sint
7197a7741afSMartin Matuska    v["zactive"] = d["zfetch_io_active"] / sint
7207a7741afSMartin Matuska
7217a7741afSMartin Matuska    # ARC structural breakdown, ARC types breakdown, ARC states breakdown
7227a7741afSMartin Matuska    v["cachessz"] = cur["caches_size"]
7237a7741afSMartin Matuska    for fs in fieldstats:
7247a7741afSMartin Matuska        fields, stats = fs[0], fs[1:]
7257a7741afSMartin Matuska        for field, fieldval in fields.items():
7267a7741afSMartin Matuska            for group in stats:
7277a7741afSMartin Matuska                for stat, statval in group.items():
7287a7741afSMartin Matuska                    if stat in ["fields", "percent"] or \
7297a7741afSMartin Matuska                        ("fields" in group and field not in group["fields"]):
7307a7741afSMartin Matuska                        continue
7317a7741afSMartin Matuska                    colname = field + stat
7327a7741afSMartin Matuska                    v[colname] = cur[fieldval[0] + statval[0]]
7337a7741afSMartin Matuska                    if "percent" in group:
7347a7741afSMartin Matuska                        v[colname + "%"] = 100 * v[colname] / \
7357a7741afSMartin Matuska                            v[group["percent"]] if v[group["percent"]] > 0 else 0
736716fd348SMartin Matuska
737716fd348SMartin Matuska    if l2exist:
7387a7741afSMartin Matuska        v["l2hits"] = d["l2_hits"] / sint
7397a7741afSMartin Matuska        v["l2miss"] = d["l2_misses"] / sint
740716fd348SMartin Matuska        v["l2read"] = v["l2hits"] + v["l2miss"]
7417a7741afSMartin Matuska        v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0
742716fd348SMartin Matuska
743716fd348SMartin Matuska        v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
744716fd348SMartin Matuska        v["l2asize"] = cur["l2_asize"]
745716fd348SMartin Matuska        v["l2size"] = cur["l2_size"]
7467a7741afSMartin Matuska        v["l2bytes"] = d["l2_read_bytes"] / sint
7477a7741afSMartin Matuska        v["l2wbytes"] = d["l2_write_bytes"] / sint
748716fd348SMartin Matuska
749716fd348SMartin Matuska        v["l2pref"] = cur["l2_prefetch_asize"]
750716fd348SMartin Matuska        v["l2mfu"] = cur["l2_mfu_asize"]
751716fd348SMartin Matuska        v["l2mru"] = cur["l2_mru_asize"]
752716fd348SMartin Matuska        v["l2data"] = cur["l2_bufc_data_asize"]
753716fd348SMartin Matuska        v["l2meta"] = cur["l2_bufc_metadata_asize"]
7547a7741afSMartin Matuska        v["l2pref%"] = 100 * v["l2pref"] / v["l2asize"]
7557a7741afSMartin Matuska        v["l2mfu%"] = 100 * v["l2mfu"] / v["l2asize"]
7567a7741afSMartin Matuska        v["l2mru%"] = 100 * v["l2mru"] / v["l2asize"]
7577a7741afSMartin Matuska        v["l2data%"] = 100 * v["l2data"] / v["l2asize"]
7587a7741afSMartin Matuska        v["l2meta%"] = 100 * v["l2meta"] / v["l2asize"]
759716fd348SMartin Matuska
760716fd348SMartin Matuska    v["grow"] = 0 if cur["arc_no_grow"] else 1
761716fd348SMartin Matuska    v["need"] = cur["arc_need_free"]
762716fd348SMartin Matuska    v["free"] = cur["memory_free_bytes"]
763716fd348SMartin Matuska    v["avail"] = cur["memory_available_bytes"]
764716fd348SMartin Matuska    v["waste"] = cur["abd_chunk_waste_size"]
765716fd348SMartin Matuska
766716fd348SMartin Matuska
767716fd348SMartin Matuskadef main():
768716fd348SMartin Matuska    global sint
769716fd348SMartin Matuska    global count
770716fd348SMartin Matuska    global hdr_intr
771716fd348SMartin Matuska
772716fd348SMartin Matuska    i = 0
773716fd348SMartin Matuska    count_flag = 0
774716fd348SMartin Matuska
775716fd348SMartin Matuska    init()
776716fd348SMartin Matuska    if count > 0:
777716fd348SMartin Matuska        count_flag = 1
778716fd348SMartin Matuska
779716fd348SMartin Matuska    signal(SIGINT, SIG_DFL)
780716fd348SMartin Matuska    signal(SIGWINCH, resize_handler)
781716fd348SMartin Matuska    while True:
782716fd348SMartin Matuska        if i == 0:
783716fd348SMartin Matuska            print_header()
784716fd348SMartin Matuska
785716fd348SMartin Matuska        snap_stats()
786716fd348SMartin Matuska        calculate()
787716fd348SMartin Matuska        print_values()
788716fd348SMartin Matuska
789716fd348SMartin Matuska        if count_flag == 1:
790716fd348SMartin Matuska            if count <= 1:
791716fd348SMartin Matuska                break
792716fd348SMartin Matuska            count -= 1
793716fd348SMartin Matuska
794716fd348SMartin Matuska        i = 0 if i >= hdr_intr else i + 1
795716fd348SMartin Matuska        time.sleep(sint)
796716fd348SMartin Matuska
797716fd348SMartin Matuska    if out:
798716fd348SMartin Matuska        out.close()
799716fd348SMartin Matuska
800716fd348SMartin Matuska
801716fd348SMartin Matuskaif __name__ == '__main__':
802716fd348SMartin Matuska    main()
803