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