diff options
Diffstat (limited to 'sys/contrib/openzfs/cmd/zarcstat.in')
-rwxr-xr-x | sys/contrib/openzfs/cmd/zarcstat.in | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/sys/contrib/openzfs/cmd/zarcstat.in b/sys/contrib/openzfs/cmd/zarcstat.in new file mode 100755 index 000000000000..8ffd20481166 --- /dev/null +++ b/sys/contrib/openzfs/cmd/zarcstat.in @@ -0,0 +1,805 @@ +#!/usr/bin/env @PYTHON_SHEBANG@ +# SPDX-License-Identifier: CDDL-1.0 +# +# Print out ZFS ARC Statistics exported via kstat(1) +# For a definition of fields, or usage, use zarcstat -v +# +# This script was originally a fork of the original arcstat.pl (0.1) +# by Neelakanth Nadgir, originally published on his Sun blog on +# 09/18/2007 +# http://blogs.sun.com/realneel/entry/zfs_arc_statistics +# +# A new version aimed to improve upon the original by adding features +# and fixing bugs as needed. This version was maintained by Mike +# Harsch and was hosted in a public open source repository: +# http://github.com/mharsch/arcstat +# +# but has since moved to the illumos-gate repository. +# +# This Python port was written by John Hixson for FreeNAS, introduced +# in commit e2c29f: +# https://github.com/freenas/freenas +# +# and has been improved by many people since. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Fields have a fixed width. Every interval, we fill the "v" +# hash with its corresponding value (v[field]=value) using calculate(). +# @hdr is the array of fields that needs to be printed, so we +# just iterate over this array and print the values using our pretty printer. +# +# This script must remain compatible with Python 3.6+. +# + +import sys +import time +import getopt +import re +import copy +import os + +from signal import signal, SIGINT, SIGWINCH, SIG_DFL + + +cols = { + # HDR: [Size, Scale, Description] + "time": [8, -1, "Time"], + "hits": [4, 1000, "ARC hits per second"], + "iohs": [4, 1000, "ARC I/O hits per second"], + "miss": [4, 1000, "ARC misses per second"], + "read": [4, 1000, "Total ARC accesses per second"], + "hit%": [4, 100, "ARC hit percentage"], + "ioh%": [4, 100, "ARC I/O hit percentage"], + "miss%": [5, 100, "ARC miss percentage"], + "dhit": [4, 1000, "Demand hits per second"], + "dioh": [4, 1000, "Demand I/O hits per second"], + "dmis": [4, 1000, "Demand misses per second"], + "dh%": [3, 100, "Demand hit percentage"], + "di%": [3, 100, "Demand I/O hit percentage"], + "dm%": [3, 100, "Demand miss percentage"], + "ddhit": [5, 1000, "Demand data hits per second"], + "ddioh": [5, 1000, "Demand data I/O hits per second"], + "ddmis": [5, 1000, "Demand data misses per second"], + "ddh%": [4, 100, "Demand data hit percentage"], + "ddi%": [4, 100, "Demand data I/O hit percentage"], + "ddm%": [4, 100, "Demand data miss percentage"], + "dmhit": [5, 1000, "Demand metadata hits per second"], + "dmioh": [5, 1000, "Demand metadata I/O hits per second"], + "dmmis": [5, 1000, "Demand metadata misses per second"], + "dmh%": [4, 100, "Demand metadata hit percentage"], + "dmi%": [4, 100, "Demand metadata I/O hit percentage"], + "dmm%": [4, 100, "Demand metadata miss percentage"], + "phit": [4, 1000, "Prefetch hits per second"], + "pioh": [4, 1000, "Prefetch I/O hits per second"], + "pmis": [4, 1000, "Prefetch misses per second"], + "ph%": [3, 100, "Prefetch hits percentage"], + "pi%": [3, 100, "Prefetch I/O hits percentage"], + "pm%": [3, 100, "Prefetch miss percentage"], + "pdhit": [5, 1000, "Prefetch data hits per second"], + "pdioh": [5, 1000, "Prefetch data I/O hits per second"], + "pdmis": [5, 1000, "Prefetch data misses per second"], + "pdh%": [4, 100, "Prefetch data hits percentage"], + "pdi%": [4, 100, "Prefetch data I/O hits percentage"], + "pdm%": [4, 100, "Prefetch data miss percentage"], + "pmhit": [5, 1000, "Prefetch metadata hits per second"], + "pmioh": [5, 1000, "Prefetch metadata I/O hits per second"], + "pmmis": [5, 1000, "Prefetch metadata misses per second"], + "pmh%": [4, 100, "Prefetch metadata hits percentage"], + "pmi%": [4, 100, "Prefetch metadata I/O hits percentage"], + "pmm%": [4, 100, "Prefetch metadata miss percentage"], + "mhit": [4, 1000, "Metadata hits per second"], + "mioh": [4, 1000, "Metadata I/O hits per second"], + "mmis": [4, 1000, "Metadata misses per second"], + "mread": [5, 1000, "Metadata accesses per second"], + "mh%": [3, 100, "Metadata hit percentage"], + "mi%": [3, 100, "Metadata I/O hit percentage"], + "mm%": [3, 100, "Metadata miss percentage"], + "arcsz": [5, 1024, "ARC size"], + "size": [5, 1024, "ARC size"], + "c": [5, 1024, "ARC target size"], + "mfu": [4, 1000, "MFU list hits per second"], + "mru": [4, 1000, "MRU list hits per second"], + "mfug": [4, 1000, "MFU ghost list hits per second"], + "mrug": [4, 1000, "MRU ghost list hits per second"], + "unc": [4, 1000, "Uncached list hits per second"], + "eskip": [5, 1000, "evict_skip per second"], + "el2skip": [7, 1000, "evict skip, due to l2 writes, per second"], + "el2cach": [7, 1024, "Size of L2 cached evictions per second"], + "el2el": [5, 1024, "Size of L2 eligible evictions per second"], + "el2mfu": [6, 1024, "Size of L2 eligible MFU evictions per second"], + "el2mru": [6, 1024, "Size of L2 eligible MRU evictions per second"], + "el2inel": [7, 1024, "Size of L2 ineligible evictions per second"], + "mtxmis": [6, 1000, "mutex_miss per second"], + "dread": [5, 1000, "Demand accesses per second"], + "ddread": [6, 1000, "Demand data accesses per second"], + "dmread": [6, 1000, "Demand metadata accesses per second"], + "pread": [5, 1000, "Prefetch accesses per second"], + "pdread": [6, 1000, "Prefetch data accesses per second"], + "pmread": [6, 1000, "Prefetch metadata accesses per second"], + "l2hits": [6, 1000, "L2ARC hits per second"], + "l2miss": [6, 1000, "L2ARC misses per second"], + "l2read": [6, 1000, "Total L2ARC accesses per second"], + "l2hit%": [6, 100, "L2ARC access hit percentage"], + "l2miss%": [7, 100, "L2ARC access miss percentage"], + "l2pref": [6, 1024, "L2ARC prefetch allocated size"], + "l2mfu": [5, 1024, "L2ARC MFU allocated size"], + "l2mru": [5, 1024, "L2ARC MRU allocated size"], + "l2data": [6, 1024, "L2ARC data allocated size"], + "l2meta": [6, 1024, "L2ARC metadata allocated size"], + "l2pref%": [7, 100, "L2ARC prefetch percentage"], + "l2mfu%": [6, 100, "L2ARC MFU percentage"], + "l2mru%": [6, 100, "L2ARC MRU percentage"], + "l2data%": [7, 100, "L2ARC data percentage"], + "l2meta%": [7, 100, "L2ARC metadata percentage"], + "l2asize": [7, 1024, "Actual (compressed) size of the L2ARC"], + "l2size": [6, 1024, "Size of the L2ARC"], + "l2bytes": [7, 1024, "Bytes read per second from the L2ARC"], + "l2wbytes": [8, 1024, "Bytes written per second to the L2ARC"], + "grow": [4, 1000, "ARC grow disabled"], + "need": [5, 1024, "ARC reclaim need"], + "free": [5, 1024, "ARC free memory"], + "avail": [5, 1024, "ARC available memory"], + "waste": [5, 1024, "Wasted memory due to round up to pagesize"], + "ztotal": [6, 1000, "zfetch total prefetcher calls per second"], + "zhits": [5, 1000, "zfetch stream hits per second"], + "zahead": [6, 1000, "zfetch hits ahead of streams per second"], + "zpast": [5, 1000, "zfetch hits behind streams per second"], + "zmisses": [7, 1000, "zfetch stream misses per second"], + "zmax": [4, 1000, "zfetch limit reached per second"], + "zfuture": [7, 1000, "zfetch stream future per second"], + "zstride": [7, 1000, "zfetch stream strides per second"], + "zissued": [7, 1000, "zfetch prefetches issued per second"], + "zactive": [7, 1000, "zfetch prefetches active per second"], +} + +# ARC structural breakdown from zarcsummary +structfields = { + "cmp": ["compressed", "Compressed"], + "ovh": ["overhead", "Overhead"], + "bon": ["bonus", "Bonus"], + "dno": ["dnode", "Dnode"], + "dbu": ["dbuf", "Dbuf"], + "hdr": ["hdr", "Header"], + "l2h": ["l2_hdr", "L2 header"], + "abd": ["abd_chunk_waste", "ABD chunk waste"], +} +structstats = { # size stats + "percent": "size", # percentage of this value + "sz": ["_size", "size"], +} + +# ARC types breakdown from zarcsummary +typefields = { + "data": ["data", "ARC data"], + "meta": ["metadata", "ARC metadata"], +} +typestats = { # size stats + "percent": "cachessz", # percentage of this value + "tg": ["_target", "target"], + "sz": ["_size", "size"], +} + +# ARC states breakdown from zarcsummary +statefields = { + "ano": ["anon", "Anonymous"], + "mfu": ["mfu", "MFU"], + "mru": ["mru", "MRU"], + "unc": ["uncached", "Uncached"], +} +targetstats = { + "percent": "cachessz", # percentage of this value + "fields": ["mfu", "mru"], # only applicable to these fields + "tg": ["_target", "target"], + "dt": ["_data_target", "data target"], + "mt": ["_metadata_target", "metadata target"], +} +statestats = { # size stats + "percent": "cachessz", # percentage of this value + "sz": ["_size", "size"], + "da": ["_data", "data size"], + "me": ["_metadata", "metadata size"], + "ed": ["_evictable_data", "evictable data size"], + "em": ["_evictable_metadata", "evictable metadata size"], +} +ghoststats = { + "fields": ["mfu", "mru"], # only applicable to these fields + "gsz": ["_ghost_size", "ghost size"], + "gd": ["_ghost_data", "ghost data size"], + "gm": ["_ghost_metadata", "ghost metadata size"], +} + +# fields and stats +fieldstats = [ + [structfields, structstats], + [typefields, typestats], + [statefields, targetstats, statestats, ghoststats], +] +for fs in fieldstats: + fields, stats = fs[0], fs[1:] + for field, fieldval in fields.items(): + for group in stats: + for stat, statval in group.items(): + if stat in ["fields", "percent"] or \ + ("fields" in group and field not in group["fields"]): + continue + colname = field + stat + coldesc = fieldval[1] + " " + statval[1] + cols[colname] = [len(colname), 1024, coldesc] + if "percent" in group: + cols[colname + "%"] = [len(colname) + 1, 100, \ + coldesc + " percentage"] + +v = {} +hdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%", + "size", "c", "avail"] +xhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis", + "dread", "pread", "read"] +zhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax", + "zfuture", "zstride", "zissued", "zactive"] +sint = 1 # Default interval is 1 second +count = 1 # Default count is 1 +hdr_intr = 20 # Print header every 20 lines of output +opfile = None +sep = " " # Default separator is 2 spaces +l2exist = False +cmd = ("Usage: zarcstat [-havxp] [-f fields] [-o file] [-s string] [interval " + "[count]]\n") +cur = {} +d = {} +out = None +kstat = None +pretty_print = True + + +if sys.platform.startswith('freebsd'): + # Requires py-sysctl on FreeBSD + import sysctl + + def kstat_update(): + global kstat + + k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats') + if ctl.type != sysctl.CTLTYPE_NODE] + k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats') + if ctl.type != sysctl.CTLTYPE_NODE] + + if not k: + sys.exit(1) + + kstat = {} + + for s in k: + if not s: + continue + + name, value = s.name, s.value + + if "arcstats" in name: + # Trims 'kstat.zfs.misc.arcstats' from the name + kstat[name[24:]] = int(value) + else: + kstat["zfetch_" + name[27:]] = int(value) + +elif sys.platform.startswith('linux'): + def kstat_update(): + global kstat + + k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')] + + k2 = ["zfetch_" + line.strip() for line in + open('/proc/spl/kstat/zfs/zfetchstats')] + + if k1 is None or k2 is None: + sys.exit(1) + + del k1[0:2] + del k2[0:2] + k = k1 + k2 + kstat = {} + + for s in k: + if not s: + continue + + name, unused, value = s.split() + kstat[name] = int(value) + + +def detailed_usage(): + sys.stderr.write("%s\n" % cmd) + sys.stderr.write("Field definitions are as follows:\n") + for key in cols: + sys.stderr.write("%11s : %s\n" % (key, cols[key][2])) + sys.stderr.write("\n") + + sys.exit(0) + + +def usage(): + sys.stderr.write("%s\n" % cmd) + sys.stderr.write("\t -h : Print this help message\n") + sys.stderr.write("\t -a : Print all possible stats\n") + sys.stderr.write("\t -v : List all possible field headers and definitions" + "\n") + sys.stderr.write("\t -x : Print extended stats\n") + sys.stderr.write("\t -z : Print zfetch stats\n") + sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n") + sys.stderr.write("\t -o : Redirect output to the specified file\n") + sys.stderr.write("\t -s : Override default field separator with custom " + "character or string\n") + sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n") + sys.stderr.write("\nExamples:\n") + sys.stderr.write("\tzarcstat -o /tmp/a.log 2 10\n") + sys.stderr.write("\tzarcstat -s \",\" -o /tmp/a.log 2 10\n") + sys.stderr.write("\tzarcstat -v\n") + sys.stderr.write("\tzarcstat -f time,hit%,dh%,ph%,mh% 1\n") + sys.stderr.write("\n") + + sys.exit(1) + + +def snap_stats(): + global cur + global kstat + + prev = copy.deepcopy(cur) + kstat_update() + + cur = kstat + + # fill in additional values from zarcsummary + cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\ + cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\ + cur["uncached_data"]+cur["uncached_metadata"] + s = 4294967296 + pd = cur["pd"] + pm = cur["pm"] + meta = cur["meta"] + v = (s-int(pd))*(s-int(meta))/s + cur["mfu_data_target"] = v / 65536 * caches_size / 65536 + v = (s-int(pm))*int(meta)/s + cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536 + v = int(pd)*(s-int(meta))/s + cur["mru_data_target"] = v / 65536 * caches_size / 65536 + v = int(pm)*int(meta)/s + cur["mru_metadata_target"] = v / 65536 * caches_size / 65536 + + cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"] + cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"] + cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"] + cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"] + + for key in cur: + if re.match(key, "class"): + continue + if key in prev: + d[key] = cur[key] - prev[key] + else: + d[key] = cur[key] + + +def isint(num): + if isinstance(num, float): + return num.is_integer() + if isinstance(num, int): + return True + return False + + +def prettynum(sz, scale, num=0): + suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z'] + index = 0 + + # Special case for date field + if scale == -1: + return "%s" % num + + if scale != 100: + while abs(num) > scale and index < 5: + num = num / scale + index += 1 + + width = sz - (0 if index == 0 else 1) + intlen = len("%.0f" % num) # %.0f rounds to nearest int + if sint == 1 and isint(num) or width < intlen + 2: + decimal = 0 + else: + decimal = 1 + return "%*.*f%s" % (width, decimal, num, suffix[index]) + + +def print_values(): + global hdr + global sep + global v + global pretty_print + + if pretty_print: + fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col]) + else: + fmt = lambda col: str(v[col]) + + sys.stdout.write(sep.join(fmt(col) for col in hdr)) + sys.stdout.write("\n") + sys.stdout.flush() + + +def print_header(): + global hdr + global sep + global pretty_print + + if pretty_print: + fmt = lambda col: "%*s" % (cols[col][0], col) + else: + fmt = lambda col: col + + sys.stdout.write(sep.join(fmt(col) for col in hdr)) + sys.stdout.write("\n") + + +def get_terminal_lines(): + try: + import fcntl + import termios + import struct + data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234') + sz = struct.unpack('hh', data) + return sz[0] + except Exception: + pass + + +def update_hdr_intr(): + global hdr_intr + + lines = get_terminal_lines() + if lines and lines > 3: + hdr_intr = lines - 3 + + +def resize_handler(signum, frame): + update_hdr_intr() + + +def init(): + global sint + global count + global hdr + global xhdr + global zhdr + global opfile + global sep + global out + global l2exist + global pretty_print + + desired_cols = None + aflag = False + xflag = False + hflag = False + vflag = False + zflag = False + i = 1 + + try: + opts, args = getopt.getopt( + sys.argv[1:], + "axzo:hvs:f:p", + [ + "all", + "extended", + "zfetch", + "outfile", + "help", + "verbose", + "separator", + "columns", + "parsable" + ] + ) + except getopt.error as msg: + sys.stderr.write("Error: %s\n" % str(msg)) + usage() + opts = None + + for opt, arg in opts: + if opt in ('-a', '--all'): + aflag = True + if opt in ('-x', '--extended'): + xflag = True + if opt in ('-o', '--outfile'): + opfile = arg + i += 1 + if opt in ('-h', '--help'): + hflag = True + if opt in ('-v', '--verbose'): + vflag = True + if opt in ('-s', '--separator'): + sep = arg + i += 1 + if opt in ('-f', '--columns'): + desired_cols = arg + i += 1 + if opt in ('-p', '--parsable'): + pretty_print = False + if opt in ('-z', '--zfetch'): + zflag = True + i += 1 + + argv = sys.argv[i:] + sint = int(argv[0]) if argv else sint + count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1) + + if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols): + usage() + + if vflag: + detailed_usage() + + if xflag: + hdr = xhdr + + if zflag: + hdr = zhdr + + update_hdr_intr() + + # check if L2ARC exists + snap_stats() + l2_size = cur.get("l2_size") + if l2_size: + l2exist = True + + if desired_cols: + hdr = desired_cols.split(",") + + invalid = [] + incompat = [] + for ele in hdr: + if ele not in cols: + invalid.append(ele) + elif not l2exist and ele.startswith("l2"): + sys.stdout.write("No L2ARC Here\n%s\n" % ele) + incompat.append(ele) + + if len(invalid) > 0: + sys.stderr.write("Invalid column definition! -- %s\n" % invalid) + usage() + + if len(incompat) > 0: + sys.stderr.write("Incompatible field specified! -- %s\n" % + incompat) + usage() + + if aflag: + if l2exist: + hdr = cols.keys() + else: + hdr = [col for col in cols.keys() if not col.startswith("l2")] + + if opfile: + try: + out = open(opfile, "w") + sys.stdout = out + + except IOError: + sys.stderr.write("Cannot open %s for writing\n" % opfile) + sys.exit(1) + + +def calculate(): + global d + global v + global l2exist + + v = dict() + v["time"] = time.strftime("%H:%M:%S", time.localtime()) + v["hits"] = d["hits"] / sint + v["iohs"] = d["iohits"] / sint + v["miss"] = d["misses"] / sint + v["read"] = v["hits"] + v["iohs"] + v["miss"] + v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0 + v["ioh%"] = 100 * v["iohs"] / v["read"] if v["read"] > 0 else 0 + v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0 + + v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint + v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) / sint + v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint + + v["dread"] = v["dhit"] + v["dioh"] + v["dmis"] + v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0 + v["di%"] = 100 * v["dioh"] / v["dread"] if v["dread"] > 0 else 0 + v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0 + + v["ddhit"] = d["demand_data_hits"] / sint + v["ddioh"] = d["demand_data_iohits"] / sint + v["ddmis"] = d["demand_data_misses"] / sint + + v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"] + v["ddh%"] = 100 * v["ddhit"] / v["ddread"] if v["ddread"] > 0 else 0 + v["ddi%"] = 100 * v["ddioh"] / v["ddread"] if v["ddread"] > 0 else 0 + v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0 + + v["dmhit"] = d["demand_metadata_hits"] / sint + v["dmioh"] = d["demand_metadata_iohits"] / sint + v["dmmis"] = d["demand_metadata_misses"] / sint + + v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"] + v["dmh%"] = 100 * v["dmhit"] / v["dmread"] if v["dmread"] > 0 else 0 + v["dmi%"] = 100 * v["dmioh"] / v["dmread"] if v["dmread"] > 0 else 0 + v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0 + + v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint + v["pioh"] = (d["prefetch_data_iohits"] + + d["prefetch_metadata_iohits"]) / sint + v["pmis"] = (d["prefetch_data_misses"] + + d["prefetch_metadata_misses"]) / sint + + v["pread"] = v["phit"] + v["pioh"] + v["pmis"] + v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0 + v["pi%"] = 100 * v["pioh"] / v["pread"] if v["pread"] > 0 else 0 + v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0 + + v["pdhit"] = d["prefetch_data_hits"] / sint + v["pdioh"] = d["prefetch_data_iohits"] / sint + v["pdmis"] = d["prefetch_data_misses"] / sint + + v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"] + v["pdh%"] = 100 * v["pdhit"] / v["pdread"] if v["pdread"] > 0 else 0 + v["pdi%"] = 100 * v["pdioh"] / v["pdread"] if v["pdread"] > 0 else 0 + v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0 + + v["pmhit"] = d["prefetch_metadata_hits"] / sint + v["pmioh"] = d["prefetch_metadata_iohits"] / sint + v["pmmis"] = d["prefetch_metadata_misses"] / sint + + v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"] + v["pmh%"] = 100 * v["pmhit"] / v["pmread"] if v["pmread"] > 0 else 0 + v["pmi%"] = 100 * v["pmioh"] / v["pmread"] if v["pmread"] > 0 else 0 + v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0 + + v["mhit"] = (d["prefetch_metadata_hits"] + + d["demand_metadata_hits"]) / sint + v["mioh"] = (d["prefetch_metadata_iohits"] + + d["demand_metadata_iohits"]) / sint + v["mmis"] = (d["prefetch_metadata_misses"] + + d["demand_metadata_misses"]) / sint + + v["mread"] = v["mhit"] + v["mioh"] + v["mmis"] + v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0 + v["mi%"] = 100 * v["mioh"] / v["mread"] if v["mread"] > 0 else 0 + v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0 + + v["arcsz"] = cur["size"] + v["size"] = cur["size"] + v["c"] = cur["c"] + v["mfu"] = d["mfu_hits"] / sint + v["mru"] = d["mru_hits"] / sint + v["mrug"] = d["mru_ghost_hits"] / sint + v["mfug"] = d["mfu_ghost_hits"] / sint + v["unc"] = d["uncached_hits"] / sint + v["eskip"] = d["evict_skip"] / sint + v["el2skip"] = d["evict_l2_skip"] / sint + v["el2cach"] = d["evict_l2_cached"] / sint + v["el2el"] = d["evict_l2_eligible"] / sint + v["el2mfu"] = d["evict_l2_eligible_mfu"] / sint + v["el2mru"] = d["evict_l2_eligible_mru"] / sint + v["el2inel"] = d["evict_l2_ineligible"] / sint + v["mtxmis"] = d["mutex_miss"] / sint + v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] + + d["zfetch_past"] + d["zfetch_misses"]) / sint + v["zhits"] = d["zfetch_hits"] / sint + v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) / sint + v["zpast"] = d["zfetch_past"] / sint + v["zmisses"] = d["zfetch_misses"] / sint + v["zmax"] = d["zfetch_max_streams"] / sint + v["zfuture"] = d["zfetch_future"] / sint + v["zstride"] = d["zfetch_stride"] / sint + v["zissued"] = d["zfetch_io_issued"] / sint + v["zactive"] = d["zfetch_io_active"] / sint + + # ARC structural breakdown, ARC types breakdown, ARC states breakdown + v["cachessz"] = cur["caches_size"] + for fs in fieldstats: + fields, stats = fs[0], fs[1:] + for field, fieldval in fields.items(): + for group in stats: + for stat, statval in group.items(): + if stat in ["fields", "percent"] or \ + ("fields" in group and field not in group["fields"]): + continue + colname = field + stat + v[colname] = cur[fieldval[0] + statval[0]] + if "percent" in group: + v[colname + "%"] = 100 * v[colname] / \ + v[group["percent"]] if v[group["percent"]] > 0 else 0 + + if l2exist: + l2asize = cur["l2_asize"] + v["l2hits"] = d["l2_hits"] / sint + v["l2miss"] = d["l2_misses"] / sint + v["l2read"] = v["l2hits"] + v["l2miss"] + v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0 + + v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0 + v["l2asize"] = l2asize + v["l2size"] = cur["l2_size"] + v["l2bytes"] = d["l2_read_bytes"] / sint + v["l2wbytes"] = d["l2_write_bytes"] / sint + + v["l2pref"] = cur["l2_prefetch_asize"] + v["l2mfu"] = cur["l2_mfu_asize"] + v["l2mru"] = cur["l2_mru_asize"] + v["l2data"] = cur["l2_bufc_data_asize"] + v["l2meta"] = cur["l2_bufc_metadata_asize"] + v["l2pref%"] = 100 * v["l2pref"] / l2asize if l2asize > 0 else 0 + v["l2mfu%"] = 100 * v["l2mfu"] / l2asize if l2asize > 0 else 0 + v["l2mru%"] = 100 * v["l2mru"] / l2asize if l2asize > 0 else 0 + v["l2data%"] = 100 * v["l2data"] / l2asize if l2asize > 0 else 0 + v["l2meta%"] = 100 * v["l2meta"] / l2asize if l2asize > 0 else 0 + + v["grow"] = 0 if cur["arc_no_grow"] else 1 + v["need"] = cur["arc_need_free"] + v["free"] = cur["memory_free_bytes"] + v["avail"] = cur["memory_available_bytes"] + v["waste"] = cur["abd_chunk_waste_size"] + + +def main(): + + global sint + global count + global hdr_intr + + i = 0 + count_flag = 0 + + init() + if count > 0: + count_flag = 1 + + signal(SIGINT, SIG_DFL) + signal(SIGWINCH, resize_handler) + while True: + if i == 0: + print_header() + + snap_stats() + calculate() + print_values() + + if count_flag == 1: + if count <= 1: + break + count -= 1 + + i = 0 if i >= hdr_intr else i + 1 + time.sleep(sint) + + if out: + out.close() + + +if __name__ == '__main__': + main() |