xref: /freebsd/sys/contrib/openzfs/cmd/zarcstat.in (revision dd32d6b29d49838c99d38ba30846ade210b2e6f7)
1*dd32d6b2SMartin Matuska#!/usr/bin/env @PYTHON_SHEBANG@
2*dd32d6b2SMartin Matuska# SPDX-License-Identifier: CDDL-1.0
3*dd32d6b2SMartin Matuska#
4*dd32d6b2SMartin Matuska# Print out ZFS ARC Statistics exported via kstat(1)
5*dd32d6b2SMartin Matuska# For a definition of fields, or usage, use zarcstat -v
6*dd32d6b2SMartin Matuska#
7*dd32d6b2SMartin Matuska# This script was originally a fork of the original arcstat.pl (0.1)
8*dd32d6b2SMartin Matuska# by Neelakanth Nadgir, originally published on his Sun blog on
9*dd32d6b2SMartin Matuska# 09/18/2007
10*dd32d6b2SMartin Matuska#     http://blogs.sun.com/realneel/entry/zfs_arc_statistics
11*dd32d6b2SMartin Matuska#
12*dd32d6b2SMartin Matuska# A new version aimed to improve upon the original by adding features
13*dd32d6b2SMartin Matuska# and fixing bugs as needed.  This version was maintained by Mike
14*dd32d6b2SMartin Matuska# Harsch and was hosted in a public open source repository:
15*dd32d6b2SMartin Matuska#    http://github.com/mharsch/arcstat
16*dd32d6b2SMartin Matuska#
17*dd32d6b2SMartin Matuska# but has since moved to the illumos-gate repository.
18*dd32d6b2SMartin Matuska#
19*dd32d6b2SMartin Matuska# This Python port was written by John Hixson for FreeNAS, introduced
20*dd32d6b2SMartin Matuska# in commit e2c29f:
21*dd32d6b2SMartin Matuska#    https://github.com/freenas/freenas
22*dd32d6b2SMartin Matuska#
23*dd32d6b2SMartin Matuska# and has been improved by many people since.
24*dd32d6b2SMartin Matuska#
25*dd32d6b2SMartin Matuska# CDDL HEADER START
26*dd32d6b2SMartin Matuska#
27*dd32d6b2SMartin Matuska# The contents of this file are subject to the terms of the
28*dd32d6b2SMartin Matuska# Common Development and Distribution License, Version 1.0 only
29*dd32d6b2SMartin Matuska# (the "License").  You may not use this file except in compliance
30*dd32d6b2SMartin Matuska# with the License.
31*dd32d6b2SMartin Matuska#
32*dd32d6b2SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
33*dd32d6b2SMartin Matuska# or https://opensource.org/licenses/CDDL-1.0.
34*dd32d6b2SMartin Matuska# See the License for the specific language governing permissions
35*dd32d6b2SMartin Matuska# and limitations under the License.
36*dd32d6b2SMartin Matuska#
37*dd32d6b2SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
38*dd32d6b2SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
39*dd32d6b2SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
40*dd32d6b2SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
41*dd32d6b2SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
42*dd32d6b2SMartin Matuska#
43*dd32d6b2SMartin Matuska# CDDL HEADER END
44*dd32d6b2SMartin Matuska#
45*dd32d6b2SMartin Matuska#
46*dd32d6b2SMartin Matuska# Fields have a fixed width. Every interval, we fill the "v"
47*dd32d6b2SMartin Matuska# hash with its corresponding value (v[field]=value) using calculate().
48*dd32d6b2SMartin Matuska# @hdr is the array of fields that needs to be printed, so we
49*dd32d6b2SMartin Matuska# just iterate over this array and print the values using our pretty printer.
50*dd32d6b2SMartin Matuska#
51*dd32d6b2SMartin Matuska# This script must remain compatible with Python 3.6+.
52*dd32d6b2SMartin Matuska#
53*dd32d6b2SMartin Matuska
54*dd32d6b2SMartin Matuskaimport sys
55*dd32d6b2SMartin Matuskaimport time
56*dd32d6b2SMartin Matuskaimport getopt
57*dd32d6b2SMartin Matuskaimport re
58*dd32d6b2SMartin Matuskaimport copy
59*dd32d6b2SMartin Matuskaimport os
60*dd32d6b2SMartin Matuska
61*dd32d6b2SMartin Matuskafrom signal import signal, SIGINT, SIGWINCH, SIG_DFL
62*dd32d6b2SMartin Matuska
63*dd32d6b2SMartin Matuska
64*dd32d6b2SMartin Matuskacols = {
65*dd32d6b2SMartin Matuska    # HDR:        [Size, Scale, Description]
66*dd32d6b2SMartin Matuska    "time":       [8, -1, "Time"],
67*dd32d6b2SMartin Matuska    "hits":       [4, 1000, "ARC hits per second"],
68*dd32d6b2SMartin Matuska    "iohs":       [4, 1000, "ARC I/O hits per second"],
69*dd32d6b2SMartin Matuska    "miss":       [4, 1000, "ARC misses per second"],
70*dd32d6b2SMartin Matuska    "read":       [4, 1000, "Total ARC accesses per second"],
71*dd32d6b2SMartin Matuska    "hit%":       [4, 100, "ARC hit percentage"],
72*dd32d6b2SMartin Matuska    "ioh%":       [4, 100, "ARC I/O hit percentage"],
73*dd32d6b2SMartin Matuska    "miss%":      [5, 100, "ARC miss percentage"],
74*dd32d6b2SMartin Matuska    "dhit":       [4, 1000, "Demand hits per second"],
75*dd32d6b2SMartin Matuska    "dioh":       [4, 1000, "Demand I/O hits per second"],
76*dd32d6b2SMartin Matuska    "dmis":       [4, 1000, "Demand misses per second"],
77*dd32d6b2SMartin Matuska    "dh%":        [3, 100, "Demand hit percentage"],
78*dd32d6b2SMartin Matuska    "di%":        [3, 100, "Demand I/O hit percentage"],
79*dd32d6b2SMartin Matuska    "dm%":        [3, 100, "Demand miss percentage"],
80*dd32d6b2SMartin Matuska    "ddhit":      [5, 1000, "Demand data hits per second"],
81*dd32d6b2SMartin Matuska    "ddioh":      [5, 1000, "Demand data I/O hits per second"],
82*dd32d6b2SMartin Matuska    "ddmis":      [5, 1000, "Demand data misses per second"],
83*dd32d6b2SMartin Matuska    "ddh%":       [4, 100, "Demand data hit percentage"],
84*dd32d6b2SMartin Matuska    "ddi%":       [4, 100, "Demand data I/O hit percentage"],
85*dd32d6b2SMartin Matuska    "ddm%":       [4, 100, "Demand data miss percentage"],
86*dd32d6b2SMartin Matuska    "dmhit":      [5, 1000, "Demand metadata hits per second"],
87*dd32d6b2SMartin Matuska    "dmioh":      [5, 1000, "Demand metadata I/O hits per second"],
88*dd32d6b2SMartin Matuska    "dmmis":      [5, 1000, "Demand metadata misses per second"],
89*dd32d6b2SMartin Matuska    "dmh%":       [4, 100, "Demand metadata hit percentage"],
90*dd32d6b2SMartin Matuska    "dmi%":       [4, 100, "Demand metadata I/O hit percentage"],
91*dd32d6b2SMartin Matuska    "dmm%":       [4, 100, "Demand metadata miss percentage"],
92*dd32d6b2SMartin Matuska    "phit":       [4, 1000, "Prefetch hits per second"],
93*dd32d6b2SMartin Matuska    "pioh":       [4, 1000, "Prefetch I/O hits per second"],
94*dd32d6b2SMartin Matuska    "pmis":       [4, 1000, "Prefetch misses per second"],
95*dd32d6b2SMartin Matuska    "ph%":        [3, 100, "Prefetch hits percentage"],
96*dd32d6b2SMartin Matuska    "pi%":        [3, 100, "Prefetch I/O hits percentage"],
97*dd32d6b2SMartin Matuska    "pm%":        [3, 100, "Prefetch miss percentage"],
98*dd32d6b2SMartin Matuska    "pdhit":      [5, 1000, "Prefetch data hits per second"],
99*dd32d6b2SMartin Matuska    "pdioh":      [5, 1000, "Prefetch data I/O hits per second"],
100*dd32d6b2SMartin Matuska    "pdmis":      [5, 1000, "Prefetch data misses per second"],
101*dd32d6b2SMartin Matuska    "pdh%":       [4, 100, "Prefetch data hits percentage"],
102*dd32d6b2SMartin Matuska    "pdi%":       [4, 100, "Prefetch data I/O hits percentage"],
103*dd32d6b2SMartin Matuska    "pdm%":       [4, 100, "Prefetch data miss percentage"],
104*dd32d6b2SMartin Matuska    "pmhit":      [5, 1000, "Prefetch metadata hits per second"],
105*dd32d6b2SMartin Matuska    "pmioh":      [5, 1000, "Prefetch metadata I/O hits per second"],
106*dd32d6b2SMartin Matuska    "pmmis":      [5, 1000, "Prefetch metadata misses per second"],
107*dd32d6b2SMartin Matuska    "pmh%":       [4, 100, "Prefetch metadata hits percentage"],
108*dd32d6b2SMartin Matuska    "pmi%":       [4, 100, "Prefetch metadata I/O hits percentage"],
109*dd32d6b2SMartin Matuska    "pmm%":       [4, 100, "Prefetch metadata miss percentage"],
110*dd32d6b2SMartin Matuska    "mhit":       [4, 1000, "Metadata hits per second"],
111*dd32d6b2SMartin Matuska    "mioh":       [4, 1000, "Metadata I/O hits per second"],
112*dd32d6b2SMartin Matuska    "mmis":       [4, 1000, "Metadata misses per second"],
113*dd32d6b2SMartin Matuska    "mread":      [5, 1000, "Metadata accesses per second"],
114*dd32d6b2SMartin Matuska    "mh%":        [3, 100, "Metadata hit percentage"],
115*dd32d6b2SMartin Matuska    "mi%":        [3, 100, "Metadata I/O hit percentage"],
116*dd32d6b2SMartin Matuska    "mm%":        [3, 100, "Metadata miss percentage"],
117*dd32d6b2SMartin Matuska    "arcsz":      [5, 1024, "ARC size"],
118*dd32d6b2SMartin Matuska    "size":       [5, 1024, "ARC size"],
119*dd32d6b2SMartin Matuska    "c":          [5, 1024, "ARC target size"],
120*dd32d6b2SMartin Matuska    "mfu":        [4, 1000, "MFU list hits per second"],
121*dd32d6b2SMartin Matuska    "mru":        [4, 1000, "MRU list hits per second"],
122*dd32d6b2SMartin Matuska    "mfug":       [4, 1000, "MFU ghost list hits per second"],
123*dd32d6b2SMartin Matuska    "mrug":       [4, 1000, "MRU ghost list hits per second"],
124*dd32d6b2SMartin Matuska    "unc":        [4, 1000, "Uncached list hits per second"],
125*dd32d6b2SMartin Matuska    "eskip":      [5, 1000, "evict_skip per second"],
126*dd32d6b2SMartin Matuska    "el2skip":    [7, 1000, "evict skip, due to l2 writes, per second"],
127*dd32d6b2SMartin Matuska    "el2cach":    [7, 1024, "Size of L2 cached evictions per second"],
128*dd32d6b2SMartin Matuska    "el2el":      [5, 1024, "Size of L2 eligible evictions per second"],
129*dd32d6b2SMartin Matuska    "el2mfu":     [6, 1024, "Size of L2 eligible MFU evictions per second"],
130*dd32d6b2SMartin Matuska    "el2mru":     [6, 1024, "Size of L2 eligible MRU evictions per second"],
131*dd32d6b2SMartin Matuska    "el2inel":    [7, 1024, "Size of L2 ineligible evictions per second"],
132*dd32d6b2SMartin Matuska    "mtxmis":     [6, 1000, "mutex_miss per second"],
133*dd32d6b2SMartin Matuska    "dread":      [5, 1000, "Demand accesses per second"],
134*dd32d6b2SMartin Matuska    "ddread":     [6, 1000, "Demand data accesses per second"],
135*dd32d6b2SMartin Matuska    "dmread":     [6, 1000, "Demand metadata accesses per second"],
136*dd32d6b2SMartin Matuska    "pread":      [5, 1000, "Prefetch accesses per second"],
137*dd32d6b2SMartin Matuska    "pdread":     [6, 1000, "Prefetch data accesses per second"],
138*dd32d6b2SMartin Matuska    "pmread":     [6, 1000, "Prefetch metadata accesses per second"],
139*dd32d6b2SMartin Matuska    "l2hits":     [6, 1000, "L2ARC hits per second"],
140*dd32d6b2SMartin Matuska    "l2miss":     [6, 1000, "L2ARC misses per second"],
141*dd32d6b2SMartin Matuska    "l2read":     [6, 1000, "Total L2ARC accesses per second"],
142*dd32d6b2SMartin Matuska    "l2hit%":     [6, 100, "L2ARC access hit percentage"],
143*dd32d6b2SMartin Matuska    "l2miss%":    [7, 100, "L2ARC access miss percentage"],
144*dd32d6b2SMartin Matuska    "l2pref":     [6, 1024, "L2ARC prefetch allocated size"],
145*dd32d6b2SMartin Matuska    "l2mfu":      [5, 1024, "L2ARC MFU allocated size"],
146*dd32d6b2SMartin Matuska    "l2mru":      [5, 1024, "L2ARC MRU allocated size"],
147*dd32d6b2SMartin Matuska    "l2data":     [6, 1024, "L2ARC data allocated size"],
148*dd32d6b2SMartin Matuska    "l2meta":     [6, 1024, "L2ARC metadata allocated size"],
149*dd32d6b2SMartin Matuska    "l2pref%":    [7, 100, "L2ARC prefetch percentage"],
150*dd32d6b2SMartin Matuska    "l2mfu%":     [6, 100, "L2ARC MFU percentage"],
151*dd32d6b2SMartin Matuska    "l2mru%":     [6, 100, "L2ARC MRU percentage"],
152*dd32d6b2SMartin Matuska    "l2data%":    [7, 100, "L2ARC data percentage"],
153*dd32d6b2SMartin Matuska    "l2meta%":    [7, 100, "L2ARC metadata percentage"],
154*dd32d6b2SMartin Matuska    "l2asize":    [7, 1024, "Actual (compressed) size of the L2ARC"],
155*dd32d6b2SMartin Matuska    "l2size":     [6, 1024, "Size of the L2ARC"],
156*dd32d6b2SMartin Matuska    "l2bytes":    [7, 1024, "Bytes read per second from the L2ARC"],
157*dd32d6b2SMartin Matuska    "l2wbytes":   [8, 1024, "Bytes written per second to the L2ARC"],
158*dd32d6b2SMartin Matuska    "grow":       [4, 1000, "ARC grow disabled"],
159*dd32d6b2SMartin Matuska    "need":       [5, 1024, "ARC reclaim need"],
160*dd32d6b2SMartin Matuska    "free":       [5, 1024, "ARC free memory"],
161*dd32d6b2SMartin Matuska    "avail":      [5, 1024, "ARC available memory"],
162*dd32d6b2SMartin Matuska    "waste":      [5, 1024, "Wasted memory due to round up to pagesize"],
163*dd32d6b2SMartin Matuska    "ztotal":     [6, 1000, "zfetch total prefetcher calls per second"],
164*dd32d6b2SMartin Matuska    "zhits":      [5, 1000, "zfetch stream hits per second"],
165*dd32d6b2SMartin Matuska    "zahead":     [6, 1000, "zfetch hits ahead of streams per second"],
166*dd32d6b2SMartin Matuska    "zpast":      [5, 1000, "zfetch hits behind streams per second"],
167*dd32d6b2SMartin Matuska    "zmisses":    [7, 1000, "zfetch stream misses per second"],
168*dd32d6b2SMartin Matuska    "zmax":       [4, 1000, "zfetch limit reached per second"],
169*dd32d6b2SMartin Matuska    "zfuture":    [7, 1000, "zfetch stream future per second"],
170*dd32d6b2SMartin Matuska    "zstride":    [7, 1000, "zfetch stream strides per second"],
171*dd32d6b2SMartin Matuska    "zissued":    [7, 1000, "zfetch prefetches issued per second"],
172*dd32d6b2SMartin Matuska    "zactive":    [7, 1000, "zfetch prefetches active per second"],
173*dd32d6b2SMartin Matuska}
174*dd32d6b2SMartin Matuska
175*dd32d6b2SMartin Matuska# ARC structural breakdown from zarcsummary
176*dd32d6b2SMartin Matuskastructfields = {
177*dd32d6b2SMartin Matuska    "cmp":      ["compressed", "Compressed"],
178*dd32d6b2SMartin Matuska    "ovh":      ["overhead", "Overhead"],
179*dd32d6b2SMartin Matuska    "bon":      ["bonus", "Bonus"],
180*dd32d6b2SMartin Matuska    "dno":      ["dnode", "Dnode"],
181*dd32d6b2SMartin Matuska    "dbu":      ["dbuf", "Dbuf"],
182*dd32d6b2SMartin Matuska    "hdr":      ["hdr", "Header"],
183*dd32d6b2SMartin Matuska    "l2h":      ["l2_hdr", "L2 header"],
184*dd32d6b2SMartin Matuska    "abd":      ["abd_chunk_waste", "ABD chunk waste"],
185*dd32d6b2SMartin Matuska}
186*dd32d6b2SMartin Matuskastructstats = {                             # size stats
187*dd32d6b2SMartin Matuska    "percent":  "size",                     # percentage of this value
188*dd32d6b2SMartin Matuska    "sz":       ["_size", "size"],
189*dd32d6b2SMartin Matuska}
190*dd32d6b2SMartin Matuska
191*dd32d6b2SMartin Matuska# ARC types breakdown from zarcsummary
192*dd32d6b2SMartin Matuskatypefields = {
193*dd32d6b2SMartin Matuska    "data":     ["data", "ARC data"],
194*dd32d6b2SMartin Matuska    "meta":     ["metadata", "ARC metadata"],
195*dd32d6b2SMartin Matuska}
196*dd32d6b2SMartin Matuskatypestats = {                               # size stats
197*dd32d6b2SMartin Matuska    "percent":  "cachessz",                 # percentage of this value
198*dd32d6b2SMartin Matuska    "tg":       ["_target", "target"],
199*dd32d6b2SMartin Matuska    "sz":       ["_size", "size"],
200*dd32d6b2SMartin Matuska}
201*dd32d6b2SMartin Matuska
202*dd32d6b2SMartin Matuska# ARC states breakdown from zarcsummary
203*dd32d6b2SMartin Matuskastatefields = {
204*dd32d6b2SMartin Matuska    "ano":      ["anon", "Anonymous"],
205*dd32d6b2SMartin Matuska    "mfu":      ["mfu", "MFU"],
206*dd32d6b2SMartin Matuska    "mru":      ["mru", "MRU"],
207*dd32d6b2SMartin Matuska    "unc":      ["uncached", "Uncached"],
208*dd32d6b2SMartin Matuska}
209*dd32d6b2SMartin Matuskatargetstats = {
210*dd32d6b2SMartin Matuska    "percent":  "cachessz",                 # percentage of this value
211*dd32d6b2SMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
212*dd32d6b2SMartin Matuska    "tg":       ["_target", "target"],
213*dd32d6b2SMartin Matuska    "dt":       ["_data_target", "data target"],
214*dd32d6b2SMartin Matuska    "mt":       ["_metadata_target", "metadata target"],
215*dd32d6b2SMartin Matuska}
216*dd32d6b2SMartin Matuskastatestats = {                              # size stats
217*dd32d6b2SMartin Matuska    "percent":  "cachessz",                 # percentage of this value
218*dd32d6b2SMartin Matuska    "sz":       ["_size", "size"],
219*dd32d6b2SMartin Matuska    "da":       ["_data", "data size"],
220*dd32d6b2SMartin Matuska    "me":       ["_metadata", "metadata size"],
221*dd32d6b2SMartin Matuska    "ed":       ["_evictable_data", "evictable data size"],
222*dd32d6b2SMartin Matuska    "em":       ["_evictable_metadata", "evictable metadata size"],
223*dd32d6b2SMartin Matuska}
224*dd32d6b2SMartin Matuskaghoststats = {
225*dd32d6b2SMartin Matuska    "fields":   ["mfu", "mru"],             # only applicable to these fields
226*dd32d6b2SMartin Matuska    "gsz":      ["_ghost_size", "ghost size"],
227*dd32d6b2SMartin Matuska    "gd":       ["_ghost_data", "ghost data size"],
228*dd32d6b2SMartin Matuska    "gm":       ["_ghost_metadata", "ghost metadata size"],
229*dd32d6b2SMartin Matuska}
230*dd32d6b2SMartin Matuska
231*dd32d6b2SMartin Matuska# fields and stats
232*dd32d6b2SMartin Matuskafieldstats = [
233*dd32d6b2SMartin Matuska    [structfields, structstats],
234*dd32d6b2SMartin Matuska    [typefields, typestats],
235*dd32d6b2SMartin Matuska    [statefields, targetstats, statestats, ghoststats],
236*dd32d6b2SMartin Matuska]
237*dd32d6b2SMartin Matuskafor fs in fieldstats:
238*dd32d6b2SMartin Matuska    fields, stats = fs[0], fs[1:]
239*dd32d6b2SMartin Matuska    for field, fieldval in fields.items():
240*dd32d6b2SMartin Matuska        for group in stats:
241*dd32d6b2SMartin Matuska            for stat, statval in group.items():
242*dd32d6b2SMartin Matuska                if stat in ["fields", "percent"] or \
243*dd32d6b2SMartin Matuska                    ("fields" in group and field not in group["fields"]):
244*dd32d6b2SMartin Matuska                    continue
245*dd32d6b2SMartin Matuska                colname = field + stat
246*dd32d6b2SMartin Matuska                coldesc = fieldval[1] + " " + statval[1]
247*dd32d6b2SMartin Matuska                cols[colname] = [len(colname), 1024, coldesc]
248*dd32d6b2SMartin Matuska                if "percent" in group:
249*dd32d6b2SMartin Matuska                    cols[colname + "%"] = [len(colname) + 1, 100, \
250*dd32d6b2SMartin Matuska                        coldesc + " percentage"]
251*dd32d6b2SMartin Matuska
252*dd32d6b2SMartin Matuskav = {}
253*dd32d6b2SMartin Matuskahdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%",
254*dd32d6b2SMartin Matuska       "size", "c", "avail"]
255*dd32d6b2SMartin Matuskaxhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis",
256*dd32d6b2SMartin Matuska        "dread", "pread", "read"]
257*dd32d6b2SMartin Matuskazhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax",
258*dd32d6b2SMartin Matuska        "zfuture", "zstride", "zissued", "zactive"]
259*dd32d6b2SMartin Matuskasint = 1               # Default interval is 1 second
260*dd32d6b2SMartin Matuskacount = 1              # Default count is 1
261*dd32d6b2SMartin Matuskahdr_intr = 20          # Print header every 20 lines of output
262*dd32d6b2SMartin Matuskaopfile = None
263*dd32d6b2SMartin Matuskasep = "  "              # Default separator is 2 spaces
264*dd32d6b2SMartin Matuskal2exist = False
265*dd32d6b2SMartin Matuskacmd = ("Usage: zarcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
266*dd32d6b2SMartin Matuska       "[count]]\n")
267*dd32d6b2SMartin Matuskacur = {}
268*dd32d6b2SMartin Matuskad = {}
269*dd32d6b2SMartin Matuskaout = None
270*dd32d6b2SMartin Matuskakstat = None
271*dd32d6b2SMartin Matuskapretty_print = True
272*dd32d6b2SMartin Matuska
273*dd32d6b2SMartin Matuska
274*dd32d6b2SMartin Matuskaif sys.platform.startswith('freebsd'):
275*dd32d6b2SMartin Matuska    # Requires py-sysctl on FreeBSD
276*dd32d6b2SMartin Matuska    import sysctl
277*dd32d6b2SMartin Matuska
278*dd32d6b2SMartin Matuska    def kstat_update():
279*dd32d6b2SMartin Matuska        global kstat
280*dd32d6b2SMartin Matuska
281*dd32d6b2SMartin Matuska        k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats')
282*dd32d6b2SMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
283*dd32d6b2SMartin Matuska        k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats')
284*dd32d6b2SMartin Matuska             if ctl.type != sysctl.CTLTYPE_NODE]
285*dd32d6b2SMartin Matuska
286*dd32d6b2SMartin Matuska        if not k:
287*dd32d6b2SMartin Matuska            sys.exit(1)
288*dd32d6b2SMartin Matuska
289*dd32d6b2SMartin Matuska        kstat = {}
290*dd32d6b2SMartin Matuska
291*dd32d6b2SMartin Matuska        for s in k:
292*dd32d6b2SMartin Matuska            if not s:
293*dd32d6b2SMartin Matuska                continue
294*dd32d6b2SMartin Matuska
295*dd32d6b2SMartin Matuska            name, value = s.name, s.value
296*dd32d6b2SMartin Matuska
297*dd32d6b2SMartin Matuska            if "arcstats" in name:
298*dd32d6b2SMartin Matuska                # Trims 'kstat.zfs.misc.arcstats' from the name
299*dd32d6b2SMartin Matuska                kstat[name[24:]] = int(value)
300*dd32d6b2SMartin Matuska            else:
301*dd32d6b2SMartin Matuska                kstat["zfetch_" + name[27:]] = int(value)
302*dd32d6b2SMartin Matuska
303*dd32d6b2SMartin Matuskaelif sys.platform.startswith('linux'):
304*dd32d6b2SMartin Matuska    def kstat_update():
305*dd32d6b2SMartin Matuska        global kstat
306*dd32d6b2SMartin Matuska
307*dd32d6b2SMartin Matuska        k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
308*dd32d6b2SMartin Matuska
309*dd32d6b2SMartin Matuska        k2 = ["zfetch_" + line.strip() for line in
310*dd32d6b2SMartin Matuska             open('/proc/spl/kstat/zfs/zfetchstats')]
311*dd32d6b2SMartin Matuska
312*dd32d6b2SMartin Matuska        if k1 is None or k2 is None:
313*dd32d6b2SMartin Matuska            sys.exit(1)
314*dd32d6b2SMartin Matuska
315*dd32d6b2SMartin Matuska        del k1[0:2]
316*dd32d6b2SMartin Matuska        del k2[0:2]
317*dd32d6b2SMartin Matuska        k = k1 + k2
318*dd32d6b2SMartin Matuska        kstat = {}
319*dd32d6b2SMartin Matuska
320*dd32d6b2SMartin Matuska        for s in k:
321*dd32d6b2SMartin Matuska            if not s:
322*dd32d6b2SMartin Matuska                continue
323*dd32d6b2SMartin Matuska
324*dd32d6b2SMartin Matuska            name, unused, value = s.split()
325*dd32d6b2SMartin Matuska            kstat[name] = int(value)
326*dd32d6b2SMartin Matuska
327*dd32d6b2SMartin Matuska
328*dd32d6b2SMartin Matuskadef detailed_usage():
329*dd32d6b2SMartin Matuska    sys.stderr.write("%s\n" % cmd)
330*dd32d6b2SMartin Matuska    sys.stderr.write("Field definitions are as follows:\n")
331*dd32d6b2SMartin Matuska    for key in cols:
332*dd32d6b2SMartin Matuska        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
333*dd32d6b2SMartin Matuska    sys.stderr.write("\n")
334*dd32d6b2SMartin Matuska
335*dd32d6b2SMartin Matuska    sys.exit(0)
336*dd32d6b2SMartin Matuska
337*dd32d6b2SMartin Matuska
338*dd32d6b2SMartin Matuskadef usage():
339*dd32d6b2SMartin Matuska    sys.stderr.write("%s\n" % cmd)
340*dd32d6b2SMartin Matuska    sys.stderr.write("\t -h : Print this help message\n")
341*dd32d6b2SMartin Matuska    sys.stderr.write("\t -a : Print all possible stats\n")
342*dd32d6b2SMartin Matuska    sys.stderr.write("\t -v : List all possible field headers and definitions"
343*dd32d6b2SMartin Matuska                     "\n")
344*dd32d6b2SMartin Matuska    sys.stderr.write("\t -x : Print extended stats\n")
345*dd32d6b2SMartin Matuska    sys.stderr.write("\t -z : Print zfetch stats\n")
346*dd32d6b2SMartin Matuska    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
347*dd32d6b2SMartin Matuska    sys.stderr.write("\t -o : Redirect output to the specified file\n")
348*dd32d6b2SMartin Matuska    sys.stderr.write("\t -s : Override default field separator with custom "
349*dd32d6b2SMartin Matuska                     "character or string\n")
350*dd32d6b2SMartin Matuska    sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n")
351*dd32d6b2SMartin Matuska    sys.stderr.write("\nExamples:\n")
352*dd32d6b2SMartin Matuska    sys.stderr.write("\tzarcstat -o /tmp/a.log 2 10\n")
353*dd32d6b2SMartin Matuska    sys.stderr.write("\tzarcstat -s \",\" -o /tmp/a.log 2 10\n")
354*dd32d6b2SMartin Matuska    sys.stderr.write("\tzarcstat -v\n")
355*dd32d6b2SMartin Matuska    sys.stderr.write("\tzarcstat -f time,hit%,dh%,ph%,mh% 1\n")
356*dd32d6b2SMartin Matuska    sys.stderr.write("\n")
357*dd32d6b2SMartin Matuska
358*dd32d6b2SMartin Matuska    sys.exit(1)
359*dd32d6b2SMartin Matuska
360*dd32d6b2SMartin Matuska
361*dd32d6b2SMartin Matuskadef snap_stats():
362*dd32d6b2SMartin Matuska    global cur
363*dd32d6b2SMartin Matuska    global kstat
364*dd32d6b2SMartin Matuska
365*dd32d6b2SMartin Matuska    prev = copy.deepcopy(cur)
366*dd32d6b2SMartin Matuska    kstat_update()
367*dd32d6b2SMartin Matuska
368*dd32d6b2SMartin Matuska    cur = kstat
369*dd32d6b2SMartin Matuska
370*dd32d6b2SMartin Matuska    # fill in additional values from zarcsummary
371*dd32d6b2SMartin Matuska    cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\
372*dd32d6b2SMartin Matuska        cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\
373*dd32d6b2SMartin Matuska        cur["uncached_data"]+cur["uncached_metadata"]
374*dd32d6b2SMartin Matuska    s = 4294967296
375*dd32d6b2SMartin Matuska    pd = cur["pd"]
376*dd32d6b2SMartin Matuska    pm = cur["pm"]
377*dd32d6b2SMartin Matuska    meta = cur["meta"]
378*dd32d6b2SMartin Matuska    v = (s-int(pd))*(s-int(meta))/s
379*dd32d6b2SMartin Matuska    cur["mfu_data_target"] = v / 65536 * caches_size / 65536
380*dd32d6b2SMartin Matuska    v = (s-int(pm))*int(meta)/s
381*dd32d6b2SMartin Matuska    cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536
382*dd32d6b2SMartin Matuska    v = int(pd)*(s-int(meta))/s
383*dd32d6b2SMartin Matuska    cur["mru_data_target"] = v / 65536 * caches_size / 65536
384*dd32d6b2SMartin Matuska    v = int(pm)*int(meta)/s
385*dd32d6b2SMartin Matuska    cur["mru_metadata_target"] = v / 65536 * caches_size / 65536
386*dd32d6b2SMartin Matuska
387*dd32d6b2SMartin Matuska    cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"]
388*dd32d6b2SMartin Matuska    cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"]
389*dd32d6b2SMartin Matuska    cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"]
390*dd32d6b2SMartin Matuska    cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"]
391*dd32d6b2SMartin Matuska
392*dd32d6b2SMartin Matuska    for key in cur:
393*dd32d6b2SMartin Matuska        if re.match(key, "class"):
394*dd32d6b2SMartin Matuska            continue
395*dd32d6b2SMartin Matuska        if key in prev:
396*dd32d6b2SMartin Matuska            d[key] = cur[key] - prev[key]
397*dd32d6b2SMartin Matuska        else:
398*dd32d6b2SMartin Matuska            d[key] = cur[key]
399*dd32d6b2SMartin Matuska
400*dd32d6b2SMartin Matuska
401*dd32d6b2SMartin Matuskadef isint(num):
402*dd32d6b2SMartin Matuska    if isinstance(num, float):
403*dd32d6b2SMartin Matuska        return num.is_integer()
404*dd32d6b2SMartin Matuska    if isinstance(num, int):
405*dd32d6b2SMartin Matuska        return True
406*dd32d6b2SMartin Matuska    return False
407*dd32d6b2SMartin Matuska
408*dd32d6b2SMartin Matuska
409*dd32d6b2SMartin Matuskadef prettynum(sz, scale, num=0):
410*dd32d6b2SMartin Matuska    suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
411*dd32d6b2SMartin Matuska    index = 0
412*dd32d6b2SMartin Matuska
413*dd32d6b2SMartin Matuska    # Special case for date field
414*dd32d6b2SMartin Matuska    if scale == -1:
415*dd32d6b2SMartin Matuska        return "%s" % num
416*dd32d6b2SMartin Matuska
417*dd32d6b2SMartin Matuska    if scale != 100:
418*dd32d6b2SMartin Matuska        while abs(num) > scale and index < 5:
419*dd32d6b2SMartin Matuska            num = num / scale
420*dd32d6b2SMartin Matuska            index += 1
421*dd32d6b2SMartin Matuska
422*dd32d6b2SMartin Matuska    width = sz - (0 if index == 0 else 1)
423*dd32d6b2SMartin Matuska    intlen = len("%.0f" % num)              # %.0f rounds to nearest int
424*dd32d6b2SMartin Matuska    if sint == 1 and isint(num) or width < intlen + 2:
425*dd32d6b2SMartin Matuska        decimal = 0
426*dd32d6b2SMartin Matuska    else:
427*dd32d6b2SMartin Matuska        decimal = 1
428*dd32d6b2SMartin Matuska    return "%*.*f%s" % (width, decimal, num, suffix[index])
429*dd32d6b2SMartin Matuska
430*dd32d6b2SMartin Matuska
431*dd32d6b2SMartin Matuskadef print_values():
432*dd32d6b2SMartin Matuska    global hdr
433*dd32d6b2SMartin Matuska    global sep
434*dd32d6b2SMartin Matuska    global v
435*dd32d6b2SMartin Matuska    global pretty_print
436*dd32d6b2SMartin Matuska
437*dd32d6b2SMartin Matuska    if pretty_print:
438*dd32d6b2SMartin Matuska        fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
439*dd32d6b2SMartin Matuska    else:
440*dd32d6b2SMartin Matuska        fmt = lambda col: str(v[col])
441*dd32d6b2SMartin Matuska
442*dd32d6b2SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
443*dd32d6b2SMartin Matuska    sys.stdout.write("\n")
444*dd32d6b2SMartin Matuska    sys.stdout.flush()
445*dd32d6b2SMartin Matuska
446*dd32d6b2SMartin Matuska
447*dd32d6b2SMartin Matuskadef print_header():
448*dd32d6b2SMartin Matuska    global hdr
449*dd32d6b2SMartin Matuska    global sep
450*dd32d6b2SMartin Matuska    global pretty_print
451*dd32d6b2SMartin Matuska
452*dd32d6b2SMartin Matuska    if pretty_print:
453*dd32d6b2SMartin Matuska        fmt = lambda col: "%*s" % (cols[col][0], col)
454*dd32d6b2SMartin Matuska    else:
455*dd32d6b2SMartin Matuska        fmt = lambda col: col
456*dd32d6b2SMartin Matuska
457*dd32d6b2SMartin Matuska    sys.stdout.write(sep.join(fmt(col) for col in hdr))
458*dd32d6b2SMartin Matuska    sys.stdout.write("\n")
459*dd32d6b2SMartin Matuska
460*dd32d6b2SMartin Matuska
461*dd32d6b2SMartin Matuskadef get_terminal_lines():
462*dd32d6b2SMartin Matuska    try:
463*dd32d6b2SMartin Matuska        import fcntl
464*dd32d6b2SMartin Matuska        import termios
465*dd32d6b2SMartin Matuska        import struct
466*dd32d6b2SMartin Matuska        data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
467*dd32d6b2SMartin Matuska        sz = struct.unpack('hh', data)
468*dd32d6b2SMartin Matuska        return sz[0]
469*dd32d6b2SMartin Matuska    except Exception:
470*dd32d6b2SMartin Matuska        pass
471*dd32d6b2SMartin Matuska
472*dd32d6b2SMartin Matuska
473*dd32d6b2SMartin Matuskadef update_hdr_intr():
474*dd32d6b2SMartin Matuska    global hdr_intr
475*dd32d6b2SMartin Matuska
476*dd32d6b2SMartin Matuska    lines = get_terminal_lines()
477*dd32d6b2SMartin Matuska    if lines and lines > 3:
478*dd32d6b2SMartin Matuska        hdr_intr = lines - 3
479*dd32d6b2SMartin Matuska
480*dd32d6b2SMartin Matuska
481*dd32d6b2SMartin Matuskadef resize_handler(signum, frame):
482*dd32d6b2SMartin Matuska    update_hdr_intr()
483*dd32d6b2SMartin Matuska
484*dd32d6b2SMartin Matuska
485*dd32d6b2SMartin Matuskadef init():
486*dd32d6b2SMartin Matuska    global sint
487*dd32d6b2SMartin Matuska    global count
488*dd32d6b2SMartin Matuska    global hdr
489*dd32d6b2SMartin Matuska    global xhdr
490*dd32d6b2SMartin Matuska    global zhdr
491*dd32d6b2SMartin Matuska    global opfile
492*dd32d6b2SMartin Matuska    global sep
493*dd32d6b2SMartin Matuska    global out
494*dd32d6b2SMartin Matuska    global l2exist
495*dd32d6b2SMartin Matuska    global pretty_print
496*dd32d6b2SMartin Matuska
497*dd32d6b2SMartin Matuska    desired_cols = None
498*dd32d6b2SMartin Matuska    aflag = False
499*dd32d6b2SMartin Matuska    xflag = False
500*dd32d6b2SMartin Matuska    hflag = False
501*dd32d6b2SMartin Matuska    vflag = False
502*dd32d6b2SMartin Matuska    zflag = False
503*dd32d6b2SMartin Matuska    i = 1
504*dd32d6b2SMartin Matuska
505*dd32d6b2SMartin Matuska    try:
506*dd32d6b2SMartin Matuska        opts, args = getopt.getopt(
507*dd32d6b2SMartin Matuska            sys.argv[1:],
508*dd32d6b2SMartin Matuska            "axzo:hvs:f:p",
509*dd32d6b2SMartin Matuska            [
510*dd32d6b2SMartin Matuska                "all",
511*dd32d6b2SMartin Matuska                "extended",
512*dd32d6b2SMartin Matuska                "zfetch",
513*dd32d6b2SMartin Matuska                "outfile",
514*dd32d6b2SMartin Matuska                "help",
515*dd32d6b2SMartin Matuska                "verbose",
516*dd32d6b2SMartin Matuska                "separator",
517*dd32d6b2SMartin Matuska                "columns",
518*dd32d6b2SMartin Matuska                "parsable"
519*dd32d6b2SMartin Matuska            ]
520*dd32d6b2SMartin Matuska        )
521*dd32d6b2SMartin Matuska    except getopt.error as msg:
522*dd32d6b2SMartin Matuska        sys.stderr.write("Error: %s\n" % str(msg))
523*dd32d6b2SMartin Matuska        usage()
524*dd32d6b2SMartin Matuska        opts = None
525*dd32d6b2SMartin Matuska
526*dd32d6b2SMartin Matuska    for opt, arg in opts:
527*dd32d6b2SMartin Matuska        if opt in ('-a', '--all'):
528*dd32d6b2SMartin Matuska            aflag = True
529*dd32d6b2SMartin Matuska        if opt in ('-x', '--extended'):
530*dd32d6b2SMartin Matuska            xflag = True
531*dd32d6b2SMartin Matuska        if opt in ('-o', '--outfile'):
532*dd32d6b2SMartin Matuska            opfile = arg
533*dd32d6b2SMartin Matuska            i += 1
534*dd32d6b2SMartin Matuska        if opt in ('-h', '--help'):
535*dd32d6b2SMartin Matuska            hflag = True
536*dd32d6b2SMartin Matuska        if opt in ('-v', '--verbose'):
537*dd32d6b2SMartin Matuska            vflag = True
538*dd32d6b2SMartin Matuska        if opt in ('-s', '--separator'):
539*dd32d6b2SMartin Matuska            sep = arg
540*dd32d6b2SMartin Matuska            i += 1
541*dd32d6b2SMartin Matuska        if opt in ('-f', '--columns'):
542*dd32d6b2SMartin Matuska            desired_cols = arg
543*dd32d6b2SMartin Matuska            i += 1
544*dd32d6b2SMartin Matuska        if opt in ('-p', '--parsable'):
545*dd32d6b2SMartin Matuska            pretty_print = False
546*dd32d6b2SMartin Matuska        if opt in ('-z', '--zfetch'):
547*dd32d6b2SMartin Matuska            zflag = True
548*dd32d6b2SMartin Matuska        i += 1
549*dd32d6b2SMartin Matuska
550*dd32d6b2SMartin Matuska    argv = sys.argv[i:]
551*dd32d6b2SMartin Matuska    sint = int(argv[0]) if argv else sint
552*dd32d6b2SMartin Matuska    count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1)
553*dd32d6b2SMartin Matuska
554*dd32d6b2SMartin Matuska    if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols):
555*dd32d6b2SMartin Matuska        usage()
556*dd32d6b2SMartin Matuska
557*dd32d6b2SMartin Matuska    if vflag:
558*dd32d6b2SMartin Matuska        detailed_usage()
559*dd32d6b2SMartin Matuska
560*dd32d6b2SMartin Matuska    if xflag:
561*dd32d6b2SMartin Matuska        hdr = xhdr
562*dd32d6b2SMartin Matuska
563*dd32d6b2SMartin Matuska    if zflag:
564*dd32d6b2SMartin Matuska        hdr = zhdr
565*dd32d6b2SMartin Matuska
566*dd32d6b2SMartin Matuska    update_hdr_intr()
567*dd32d6b2SMartin Matuska
568*dd32d6b2SMartin Matuska    # check if L2ARC exists
569*dd32d6b2SMartin Matuska    snap_stats()
570*dd32d6b2SMartin Matuska    l2_size = cur.get("l2_size")
571*dd32d6b2SMartin Matuska    if l2_size:
572*dd32d6b2SMartin Matuska        l2exist = True
573*dd32d6b2SMartin Matuska
574*dd32d6b2SMartin Matuska    if desired_cols:
575*dd32d6b2SMartin Matuska        hdr = desired_cols.split(",")
576*dd32d6b2SMartin Matuska
577*dd32d6b2SMartin Matuska        invalid = []
578*dd32d6b2SMartin Matuska        incompat = []
579*dd32d6b2SMartin Matuska        for ele in hdr:
580*dd32d6b2SMartin Matuska            if ele not in cols:
581*dd32d6b2SMartin Matuska                invalid.append(ele)
582*dd32d6b2SMartin Matuska            elif not l2exist and ele.startswith("l2"):
583*dd32d6b2SMartin Matuska                sys.stdout.write("No L2ARC Here\n%s\n" % ele)
584*dd32d6b2SMartin Matuska                incompat.append(ele)
585*dd32d6b2SMartin Matuska
586*dd32d6b2SMartin Matuska        if len(invalid) > 0:
587*dd32d6b2SMartin Matuska            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
588*dd32d6b2SMartin Matuska            usage()
589*dd32d6b2SMartin Matuska
590*dd32d6b2SMartin Matuska        if len(incompat) > 0:
591*dd32d6b2SMartin Matuska            sys.stderr.write("Incompatible field specified! -- %s\n" %
592*dd32d6b2SMartin Matuska                             incompat)
593*dd32d6b2SMartin Matuska            usage()
594*dd32d6b2SMartin Matuska
595*dd32d6b2SMartin Matuska    if aflag:
596*dd32d6b2SMartin Matuska        if l2exist:
597*dd32d6b2SMartin Matuska            hdr = cols.keys()
598*dd32d6b2SMartin Matuska        else:
599*dd32d6b2SMartin Matuska            hdr = [col for col in cols.keys() if not col.startswith("l2")]
600*dd32d6b2SMartin Matuska
601*dd32d6b2SMartin Matuska    if opfile:
602*dd32d6b2SMartin Matuska        try:
603*dd32d6b2SMartin Matuska            out = open(opfile, "w")
604*dd32d6b2SMartin Matuska            sys.stdout = out
605*dd32d6b2SMartin Matuska
606*dd32d6b2SMartin Matuska        except IOError:
607*dd32d6b2SMartin Matuska            sys.stderr.write("Cannot open %s for writing\n" % opfile)
608*dd32d6b2SMartin Matuska            sys.exit(1)
609*dd32d6b2SMartin Matuska
610*dd32d6b2SMartin Matuska
611*dd32d6b2SMartin Matuskadef calculate():
612*dd32d6b2SMartin Matuska    global d
613*dd32d6b2SMartin Matuska    global v
614*dd32d6b2SMartin Matuska    global l2exist
615*dd32d6b2SMartin Matuska
616*dd32d6b2SMartin Matuska    v = dict()
617*dd32d6b2SMartin Matuska    v["time"] = time.strftime("%H:%M:%S", time.localtime())
618*dd32d6b2SMartin Matuska    v["hits"] = d["hits"] / sint
619*dd32d6b2SMartin Matuska    v["iohs"] = d["iohits"] / sint
620*dd32d6b2SMartin Matuska    v["miss"] = d["misses"] / sint
621*dd32d6b2SMartin Matuska    v["read"] = v["hits"] + v["iohs"] + v["miss"]
622*dd32d6b2SMartin Matuska    v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0
623*dd32d6b2SMartin Matuska    v["ioh%"] = 100 * v["iohs"] / v["read"] if v["read"] > 0 else 0
624*dd32d6b2SMartin Matuska    v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0
625*dd32d6b2SMartin Matuska
626*dd32d6b2SMartin Matuska    v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint
627*dd32d6b2SMartin Matuska    v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) / sint
628*dd32d6b2SMartin Matuska    v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
629*dd32d6b2SMartin Matuska
630*dd32d6b2SMartin Matuska    v["dread"] = v["dhit"] + v["dioh"] + v["dmis"]
631*dd32d6b2SMartin Matuska    v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0
632*dd32d6b2SMartin Matuska    v["di%"] = 100 * v["dioh"] / v["dread"] if v["dread"] > 0 else 0
633*dd32d6b2SMartin Matuska    v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0
634*dd32d6b2SMartin Matuska
635*dd32d6b2SMartin Matuska    v["ddhit"] = d["demand_data_hits"] / sint
636*dd32d6b2SMartin Matuska    v["ddioh"] = d["demand_data_iohits"] / sint
637*dd32d6b2SMartin Matuska    v["ddmis"] = d["demand_data_misses"] / sint
638*dd32d6b2SMartin Matuska
639*dd32d6b2SMartin Matuska    v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"]
640*dd32d6b2SMartin Matuska    v["ddh%"] = 100 * v["ddhit"] / v["ddread"] if v["ddread"] > 0 else 0
641*dd32d6b2SMartin Matuska    v["ddi%"] = 100 * v["ddioh"] / v["ddread"] if v["ddread"] > 0 else 0
642*dd32d6b2SMartin Matuska    v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0
643*dd32d6b2SMartin Matuska
644*dd32d6b2SMartin Matuska    v["dmhit"] = d["demand_metadata_hits"] / sint
645*dd32d6b2SMartin Matuska    v["dmioh"] = d["demand_metadata_iohits"] / sint
646*dd32d6b2SMartin Matuska    v["dmmis"] = d["demand_metadata_misses"] / sint
647*dd32d6b2SMartin Matuska
648*dd32d6b2SMartin Matuska    v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"]
649*dd32d6b2SMartin Matuska    v["dmh%"] = 100 * v["dmhit"] / v["dmread"] if v["dmread"] > 0 else 0
650*dd32d6b2SMartin Matuska    v["dmi%"] = 100 * v["dmioh"] / v["dmread"] if v["dmread"] > 0 else 0
651*dd32d6b2SMartin Matuska    v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0
652*dd32d6b2SMartin Matuska
653*dd32d6b2SMartin Matuska    v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
654*dd32d6b2SMartin Matuska    v["pioh"] = (d["prefetch_data_iohits"] +
655*dd32d6b2SMartin Matuska                 d["prefetch_metadata_iohits"]) / sint
656*dd32d6b2SMartin Matuska    v["pmis"] = (d["prefetch_data_misses"] +
657*dd32d6b2SMartin Matuska                 d["prefetch_metadata_misses"]) / sint
658*dd32d6b2SMartin Matuska
659*dd32d6b2SMartin Matuska    v["pread"] = v["phit"] + v["pioh"] + v["pmis"]
660*dd32d6b2SMartin Matuska    v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0
661*dd32d6b2SMartin Matuska    v["pi%"] = 100 * v["pioh"] / v["pread"] if v["pread"] > 0 else 0
662*dd32d6b2SMartin Matuska    v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0
663*dd32d6b2SMartin Matuska
664*dd32d6b2SMartin Matuska    v["pdhit"] = d["prefetch_data_hits"] / sint
665*dd32d6b2SMartin Matuska    v["pdioh"] = d["prefetch_data_iohits"] / sint
666*dd32d6b2SMartin Matuska    v["pdmis"] = d["prefetch_data_misses"] / sint
667*dd32d6b2SMartin Matuska
668*dd32d6b2SMartin Matuska    v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"]
669*dd32d6b2SMartin Matuska    v["pdh%"] = 100 * v["pdhit"] / v["pdread"] if v["pdread"] > 0 else 0
670*dd32d6b2SMartin Matuska    v["pdi%"] = 100 * v["pdioh"] / v["pdread"] if v["pdread"] > 0 else 0
671*dd32d6b2SMartin Matuska    v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0
672*dd32d6b2SMartin Matuska
673*dd32d6b2SMartin Matuska    v["pmhit"] = d["prefetch_metadata_hits"] / sint
674*dd32d6b2SMartin Matuska    v["pmioh"] = d["prefetch_metadata_iohits"] / sint
675*dd32d6b2SMartin Matuska    v["pmmis"] = d["prefetch_metadata_misses"] / sint
676*dd32d6b2SMartin Matuska
677*dd32d6b2SMartin Matuska    v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"]
678*dd32d6b2SMartin Matuska    v["pmh%"] = 100 * v["pmhit"] / v["pmread"] if v["pmread"] > 0 else 0
679*dd32d6b2SMartin Matuska    v["pmi%"] = 100 * v["pmioh"] / v["pmread"] if v["pmread"] > 0 else 0
680*dd32d6b2SMartin Matuska    v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0
681*dd32d6b2SMartin Matuska
682*dd32d6b2SMartin Matuska    v["mhit"] = (d["prefetch_metadata_hits"] +
683*dd32d6b2SMartin Matuska                 d["demand_metadata_hits"]) / sint
684*dd32d6b2SMartin Matuska    v["mioh"] = (d["prefetch_metadata_iohits"] +
685*dd32d6b2SMartin Matuska                 d["demand_metadata_iohits"]) / sint
686*dd32d6b2SMartin Matuska    v["mmis"] = (d["prefetch_metadata_misses"] +
687*dd32d6b2SMartin Matuska                 d["demand_metadata_misses"]) / sint
688*dd32d6b2SMartin Matuska
689*dd32d6b2SMartin Matuska    v["mread"] = v["mhit"] + v["mioh"] + v["mmis"]
690*dd32d6b2SMartin Matuska    v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0
691*dd32d6b2SMartin Matuska    v["mi%"] = 100 * v["mioh"] / v["mread"] if v["mread"] > 0 else 0
692*dd32d6b2SMartin Matuska    v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0
693*dd32d6b2SMartin Matuska
694*dd32d6b2SMartin Matuska    v["arcsz"] = cur["size"]
695*dd32d6b2SMartin Matuska    v["size"] = cur["size"]
696*dd32d6b2SMartin Matuska    v["c"] = cur["c"]
697*dd32d6b2SMartin Matuska    v["mfu"] = d["mfu_hits"] / sint
698*dd32d6b2SMartin Matuska    v["mru"] = d["mru_hits"] / sint
699*dd32d6b2SMartin Matuska    v["mrug"] = d["mru_ghost_hits"] / sint
700*dd32d6b2SMartin Matuska    v["mfug"] = d["mfu_ghost_hits"] / sint
701*dd32d6b2SMartin Matuska    v["unc"] = d["uncached_hits"] / sint
702*dd32d6b2SMartin Matuska    v["eskip"] = d["evict_skip"] / sint
703*dd32d6b2SMartin Matuska    v["el2skip"] = d["evict_l2_skip"] / sint
704*dd32d6b2SMartin Matuska    v["el2cach"] = d["evict_l2_cached"] / sint
705*dd32d6b2SMartin Matuska    v["el2el"] = d["evict_l2_eligible"] / sint
706*dd32d6b2SMartin Matuska    v["el2mfu"] = d["evict_l2_eligible_mfu"] / sint
707*dd32d6b2SMartin Matuska    v["el2mru"] = d["evict_l2_eligible_mru"] / sint
708*dd32d6b2SMartin Matuska    v["el2inel"] = d["evict_l2_ineligible"] / sint
709*dd32d6b2SMartin Matuska    v["mtxmis"] = d["mutex_miss"] / sint
710*dd32d6b2SMartin Matuska    v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] +
711*dd32d6b2SMartin Matuska                   d["zfetch_past"] + d["zfetch_misses"]) / sint
712*dd32d6b2SMartin Matuska    v["zhits"] = d["zfetch_hits"] / sint
713*dd32d6b2SMartin Matuska    v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) / sint
714*dd32d6b2SMartin Matuska    v["zpast"] = d["zfetch_past"] / sint
715*dd32d6b2SMartin Matuska    v["zmisses"] = d["zfetch_misses"] / sint
716*dd32d6b2SMartin Matuska    v["zmax"] = d["zfetch_max_streams"] / sint
717*dd32d6b2SMartin Matuska    v["zfuture"] = d["zfetch_future"] / sint
718*dd32d6b2SMartin Matuska    v["zstride"] = d["zfetch_stride"] / sint
719*dd32d6b2SMartin Matuska    v["zissued"] = d["zfetch_io_issued"] / sint
720*dd32d6b2SMartin Matuska    v["zactive"] = d["zfetch_io_active"] / sint
721*dd32d6b2SMartin Matuska
722*dd32d6b2SMartin Matuska    # ARC structural breakdown, ARC types breakdown, ARC states breakdown
723*dd32d6b2SMartin Matuska    v["cachessz"] = cur["caches_size"]
724*dd32d6b2SMartin Matuska    for fs in fieldstats:
725*dd32d6b2SMartin Matuska        fields, stats = fs[0], fs[1:]
726*dd32d6b2SMartin Matuska        for field, fieldval in fields.items():
727*dd32d6b2SMartin Matuska            for group in stats:
728*dd32d6b2SMartin Matuska                for stat, statval in group.items():
729*dd32d6b2SMartin Matuska                    if stat in ["fields", "percent"] or \
730*dd32d6b2SMartin Matuska                        ("fields" in group and field not in group["fields"]):
731*dd32d6b2SMartin Matuska                        continue
732*dd32d6b2SMartin Matuska                    colname = field + stat
733*dd32d6b2SMartin Matuska                    v[colname] = cur[fieldval[0] + statval[0]]
734*dd32d6b2SMartin Matuska                    if "percent" in group:
735*dd32d6b2SMartin Matuska                        v[colname + "%"] = 100 * v[colname] / \
736*dd32d6b2SMartin Matuska                            v[group["percent"]] if v[group["percent"]] > 0 else 0
737*dd32d6b2SMartin Matuska
738*dd32d6b2SMartin Matuska    if l2exist:
739*dd32d6b2SMartin Matuska        l2asize = cur["l2_asize"]
740*dd32d6b2SMartin Matuska        v["l2hits"] = d["l2_hits"] / sint
741*dd32d6b2SMartin Matuska        v["l2miss"] = d["l2_misses"] / sint
742*dd32d6b2SMartin Matuska        v["l2read"] = v["l2hits"] + v["l2miss"]
743*dd32d6b2SMartin Matuska        v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0
744*dd32d6b2SMartin Matuska
745*dd32d6b2SMartin Matuska        v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
746*dd32d6b2SMartin Matuska        v["l2asize"] = l2asize
747*dd32d6b2SMartin Matuska        v["l2size"] = cur["l2_size"]
748*dd32d6b2SMartin Matuska        v["l2bytes"] = d["l2_read_bytes"] / sint
749*dd32d6b2SMartin Matuska        v["l2wbytes"] = d["l2_write_bytes"] / sint
750*dd32d6b2SMartin Matuska
751*dd32d6b2SMartin Matuska        v["l2pref"] = cur["l2_prefetch_asize"]
752*dd32d6b2SMartin Matuska        v["l2mfu"] = cur["l2_mfu_asize"]
753*dd32d6b2SMartin Matuska        v["l2mru"] = cur["l2_mru_asize"]
754*dd32d6b2SMartin Matuska        v["l2data"] = cur["l2_bufc_data_asize"]
755*dd32d6b2SMartin Matuska        v["l2meta"] = cur["l2_bufc_metadata_asize"]
756*dd32d6b2SMartin Matuska        v["l2pref%"] = 100 * v["l2pref"] / l2asize if l2asize > 0 else 0
757*dd32d6b2SMartin Matuska        v["l2mfu%"] = 100 * v["l2mfu"] / l2asize if l2asize > 0 else 0
758*dd32d6b2SMartin Matuska        v["l2mru%"] = 100 * v["l2mru"] / l2asize if l2asize > 0 else 0
759*dd32d6b2SMartin Matuska        v["l2data%"] = 100 * v["l2data"] / l2asize if l2asize > 0 else 0
760*dd32d6b2SMartin Matuska        v["l2meta%"] = 100 * v["l2meta"] / l2asize if l2asize > 0 else 0
761*dd32d6b2SMartin Matuska
762*dd32d6b2SMartin Matuska    v["grow"] = 0 if cur["arc_no_grow"] else 1
763*dd32d6b2SMartin Matuska    v["need"] = cur["arc_need_free"]
764*dd32d6b2SMartin Matuska    v["free"] = cur["memory_free_bytes"]
765*dd32d6b2SMartin Matuska    v["avail"] = cur["memory_available_bytes"]
766*dd32d6b2SMartin Matuska    v["waste"] = cur["abd_chunk_waste_size"]
767*dd32d6b2SMartin Matuska
768*dd32d6b2SMartin Matuska
769*dd32d6b2SMartin Matuskadef main():
770*dd32d6b2SMartin Matuska
771*dd32d6b2SMartin Matuska    global sint
772*dd32d6b2SMartin Matuska    global count
773*dd32d6b2SMartin Matuska    global hdr_intr
774*dd32d6b2SMartin Matuska
775*dd32d6b2SMartin Matuska    i = 0
776*dd32d6b2SMartin Matuska    count_flag = 0
777*dd32d6b2SMartin Matuska
778*dd32d6b2SMartin Matuska    init()
779*dd32d6b2SMartin Matuska    if count > 0:
780*dd32d6b2SMartin Matuska        count_flag = 1
781*dd32d6b2SMartin Matuska
782*dd32d6b2SMartin Matuska    signal(SIGINT, SIG_DFL)
783*dd32d6b2SMartin Matuska    signal(SIGWINCH, resize_handler)
784*dd32d6b2SMartin Matuska    while True:
785*dd32d6b2SMartin Matuska        if i == 0:
786*dd32d6b2SMartin Matuska            print_header()
787*dd32d6b2SMartin Matuska
788*dd32d6b2SMartin Matuska        snap_stats()
789*dd32d6b2SMartin Matuska        calculate()
790*dd32d6b2SMartin Matuska        print_values()
791*dd32d6b2SMartin Matuska
792*dd32d6b2SMartin Matuska        if count_flag == 1:
793*dd32d6b2SMartin Matuska            if count <= 1:
794*dd32d6b2SMartin Matuska                break
795*dd32d6b2SMartin Matuska            count -= 1
796*dd32d6b2SMartin Matuska
797*dd32d6b2SMartin Matuska        i = 0 if i >= hdr_intr else i + 1
798*dd32d6b2SMartin Matuska        time.sleep(sint)
799*dd32d6b2SMartin Matuska
800*dd32d6b2SMartin Matuska    if out:
801*dd32d6b2SMartin Matuska        out.close()
802*dd32d6b2SMartin Matuska
803*dd32d6b2SMartin Matuska
804*dd32d6b2SMartin Matuskaif __name__ == '__main__':
805*dd32d6b2SMartin Matuska    main()
806