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