]>
git.proxmox.com Git - mirror_zfs.git/blob - cmd/arcstat/arcstat.py
1 #!/usr/local/bin/python
3 # Print out ZFS ARC Statistics exported via kstat(1)
4 # For a definition of fields, or usage, use arctstat.pl -v
6 # This script is a fork of the original arcstat.pl (0.1) by
7 # Neelakanth Nadgir, originally published on his Sun blog on
9 # http://blogs.sun.com/realneel/entry/zfs_arc_statistics
11 # This version aims to improve upon the original by adding features
12 # and fixing bugs as needed. This version is maintained by
13 # Mike Harsch and is hosted in a public open source repository:
14 # http://github.com/mharsch/arcstat
16 # Comments, Questions, or Suggestions are always welcome.
17 # Contact the maintainer at ( mike at harschsystems dot com )
21 # The contents of this file are subject to the terms of the
22 # Common Development and Distribution License, Version 1.0 only
23 # (the "License"). You may not use this file except in compliance
26 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
27 # or http://www.opensolaris.org/os/licensing.
28 # See the License for the specific language governing permissions
29 # and limitations under the License.
31 # When distributing Covered Code, include this CDDL HEADER in each
32 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
33 # If applicable, add the following below this CDDL HEADER, with the
34 # fields enclosed by brackets "[]" replaced with your own identifying
35 # information: Portions Copyright [yyyy] [name of copyright owner]
40 # Fields have a fixed width. Every interval, we fill the "v"
41 # hash with its corresponding value (v[field]=value) using calculate().
42 # @hdr is the array of fields that needs to be printed, so we
43 # just iterate over this array and print the values using our pretty printer.
53 from decimal
import Decimal
54 from subprocess
import Popen
, PIPE
55 from signal
import signal
, SIGINT
58 # HDR: [Size, Scale, Description]
59 "time": [8, -1, "Time"],
60 "hits": [4, 1000, "ARC reads per second"],
61 "miss": [4, 1000, "ARC misses per second"],
62 "read": [4, 1000, "Total ARC accesses per second"],
63 "hit%": [4, 100, "ARC Hit percentage"],
64 "miss%": [5, 100, "ARC miss percentage"],
65 "dhit": [4, 1000, "Demand Data hits per second"],
66 "dmis": [4, 1000, "Demand Data misses per second"],
67 "dh%": [3, 100, "Demand Data hit percentage"],
68 "dm%": [3, 100, "Demand Data miss percentage"],
69 "phit": [4, 1000, "Prefetch hits per second"],
70 "pmis": [4, 1000, "Prefetch misses per second"],
71 "ph%": [3, 100, "Prefetch hits percentage"],
72 "pm%": [3, 100, "Prefetch miss percentage"],
73 "mhit": [4, 1000, "Metadata hits per second"],
74 "mmis": [4, 1000, "Metadata misses per second"],
75 "mread": [4, 1000, "Metadata accesses per second"],
76 "mh%": [3, 100, "Metadata hit percentage"],
77 "mm%": [3, 100, "Metadata miss percentage"],
78 "arcsz": [5, 1024, "ARC Size"],
79 "c": [4, 1024, "ARC Target Size"],
80 "mfu": [4, 1000, "MFU List hits per second"],
81 "mru": [4, 1000, "MRU List hits per second"],
82 "mfug": [4, 1000, "MFU Ghost List hits per second"],
83 "mrug": [4, 1000, "MRU Ghost List hits per second"],
84 "eskip": [5, 1000, "evict_skip per second"],
85 "mtxmis": [6, 1000, "mutex_miss per second"],
86 "rmis": [4, 1000, "recycle_miss per second"],
87 "dread": [5, 1000, "Demand data accesses per second"],
88 "pread": [5, 1000, "Prefetch accesses per second"],
89 "l2hits": [6, 1000, "L2ARC hits per second"],
90 "l2miss": [6, 1000, "L2ARC misses per second"],
91 "l2read": [6, 1000, "Total L2ARC accesses per second"],
92 "l2hit%": [6, 100, "L2ARC access hit percentage"],
93 "l2miss%": [7, 100, "L2ARC access miss percentage"],
94 "l2size": [6, 1024, "Size of the L2ARC"],
95 "l2bytes": [7, 1024, "bytes read per second from the L2ARC"],
99 hdr
= ["time", "read", "miss", "miss%", "dmis", "dm%", "pmis", "pm%", "mmis",
101 xhdr
= ["time", "mfu", "mru", "mfug", "mrug", "eskip", "mtxmis", "rmis",
102 "dread", "pread", "read"]
103 sint
= 1 # Default interval is 1 second
104 count
= 1 # Default count is 1
105 hdr_intr
= 20 # Print header every 20 lines of output
107 sep
= " " # Default separator is 2 spaces
110 cmd
= ("Usage: arcstat [-hvx] [-f fields] [-o file] [-s string] [interval "
116 float_pobj
= re
.compile("^[0-9]+(\.[0-9]+)?$")
119 def detailed_usage():
120 sys
.stderr
.write("%s\n" % cmd
)
121 sys
.stderr
.write("Field definitions are as follows:\n")
123 sys
.stderr
.write("%11s : %s\n" % (key
, cols
[key
][2]))
124 sys
.stderr
.write("\n")
130 sys
.stderr
.write("%s\n" % cmd
)
131 sys
.stderr
.write("\t -h : Print this help message\n")
132 sys
.stderr
.write("\t -v : List all possible field headers and definitions"
134 sys
.stderr
.write("\t -x : Print extended stats\n")
135 sys
.stderr
.write("\t -f : Specify specific fields to print (see -v)\n")
136 sys
.stderr
.write("\t -o : Redirect output to the specified file\n")
137 sys
.stderr
.write("\t -s : Override default field separator with custom "
138 "character or string\n")
139 sys
.stderr
.write("\nExamples:\n")
140 sys
.stderr
.write("\tarcstat -o /tmp/a.log 2 10\n")
141 sys
.stderr
.write("\tarcstat -s \",\" -o /tmp/a.log 2 10\n")
142 sys
.stderr
.write("\tarcstat -v\n")
143 sys
.stderr
.write("\tarcstat -f time,hit%,dh%,ph%,mh% 1\n")
144 sys
.stderr
.write("\n")
152 p
= Popen("/sbin/sysctl -q 'kstat.zfs.misc.arcstats'", stdin
=PIPE
,
153 stdout
=PIPE
, stderr
=PIPE
, shell
=True, close_fds
=True)
156 k
= p
.communicate()[0].split('\n')
157 if p
.returncode
!= 0:
171 name
, value
= s
.split(':')
173 value
= value
.strip()
175 parts
= name
.split('.')
178 kstat
[n
] = Decimal(value
)
185 prev
= copy
.deepcopy(cur
)
190 if re
.match(key
, "class"):
193 d
[key
] = cur
[key
] - prev
[key
]
198 def prettynum(sz
, scale
, num
=0):
199 suffix
= [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
203 # Special case for date field
207 # Rounding error, return 0
208 elif num
> 0 and num
< 1:
211 while num
> scale
and index
< 5:
217 return "%*d" % (sz
, num
)
219 if (save
/ scale
) < 10:
220 return "%*.1f%s" % (sz
- 1, num
, suffix
[index
])
222 return "%*d%s" % (sz
- 1, num
, suffix
[index
])
231 sys
.stdout
.write("%s%s" % (
232 prettynum(cols
[col
][0], cols
[col
][1], v
[col
]),
235 sys
.stdout
.write("\n")
243 sys
.stdout
.write("%*s%s" % (cols
[col
][0], col
, sep
))
244 sys
.stdout
.write("\n")
264 opts
, args
= getopt
.getopt(
277 except getopt
.error
, msg
:
278 sys
.stderr
.write(msg
)
281 for opt
, arg
in opts
:
282 if opt
in ('-x', '--extended'):
284 if opt
in ('-o', '--outfile'):
287 if opt
in ('-h', '--help'):
289 if opt
in ('-v', '--verbose'):
291 if opt
in ('-s', '--seperator'):
294 if opt
in ('-f', '--columns'):
300 sint
= Decimal(argv
[0]) if argv
else sint
301 count
= int(argv
[1]) if len(argv
) > 1 else count
304 sint
= Decimal(argv
[0])
308 sint
= Decimal(argv
[0])
311 if hflag
or (xflag
and desired_cols
):
320 # check if L2ARC exists
322 l2_size
= cur
.get("l2_size")
327 hdr
= desired_cols
.split(",")
334 elif not l2exist
and ele
.startswith("l2"):
335 sys
.stdout
.write("No L2ARC Here\n%s\n" % ele
)
339 sys
.stderr
.write("Invalid column definition! -- %s\n" % invalid
)
342 if len(incompat
) > 0:
343 sys
.stderr
.write("Incompatible field specified! -- %s\n" % (
350 out
= open(opfile
, "w")
354 sys
.stderr
.write("Cannot open %s for writing\n" % opfile
)
364 v
["time"] = time
.strftime("%H:%M:%S", time
.localtime())
365 v
["hits"] = d
["hits"] / sint
366 v
["miss"] = d
["misses"] / sint
367 v
["read"] = v
["hits"] + v
["miss"]
368 v
["hit%"] = 100 * v
["hits"] / v
["read"] if v
["read"] > 0 else 0
369 v
["miss%"] = 100 - v
["hit%"] if v
["read"] > 0 else 0
371 v
["dhit"] = (d
["demand_data_hits"] + d
["demand_metadata_hits"]) / sint
372 v
["dmis"] = (d
["demand_data_misses"] + d
["demand_metadata_misses"]) / sint
374 v
["dread"] = v
["dhit"] + v
["dmis"]
375 v
["dh%"] = 100 * v
["dhit"] / v
["dread"] if v
["dread"] > 0 else 0
376 v
["dm%"] = 100 - v
["dh%"] if v
["dread"] > 0 else 0
378 v
["phit"] = (d
["prefetch_data_hits"] + d
["prefetch_metadata_hits"]) / sint
379 v
["pmis"] = (d
["prefetch_data_misses"] +
380 d
["prefetch_metadata_misses"]) / sint
382 v
["pread"] = v
["phit"] + v
["pmis"]
383 v
["ph%"] = 100 * v
["phit"] / v
["pread"] if v
["pread"] > 0 else 0
384 v
["pm%"] = 100 - v
["ph%"] if v
["pread"] > 0 else 0
386 v
["mhit"] = (d
["prefetch_metadata_hits"] +
387 d
["demand_metadata_hits"]) / sint
388 v
["mmis"] = (d
["prefetch_metadata_misses"] +
389 d
["demand_metadata_misses"]) / sint
391 v
["mread"] = v
["mhit"] + v
["mmis"]
392 v
["mh%"] = 100 * v
["mhit"] / v
["mread"] if v
["mread"] > 0 else 0
393 v
["mm%"] = 100 - v
["mh%"] if v
["mread"] > 0 else 0
395 v
["arcsz"] = cur
["size"]
397 v
["mfu"] = d
["mfu_hits"] / sint
398 v
["mru"] = d
["mru_hits"] / sint
399 v
["mrug"] = d
["mru_ghost_hits"] / sint
400 v
["mfug"] = d
["mfu_ghost_hits"] / sint
401 v
["eskip"] = d
["evict_skip"] / sint
402 v
["rmis"] = d
["recycle_miss"] / sint
403 v
["mtxmis"] = d
["mutex_miss"] / sint
406 v
["l2hits"] = d
["l2_hits"] / sint
407 v
["l2miss"] = d
["l2_misses"] / sint
408 v
["l2read"] = v
["l2hits"] + v
["l2miss"]
409 v
["l2hit%"] = 100 * v
["l2hits"] / v
["l2read"] if v
["l2read"] > 0 else 0
411 v
["l2miss%"] = 100 - v
["l2hit%"] if v
["l2read"] > 0 else 0
412 v
["l2size"] = cur
["l2_size"]
413 v
["l2bytes"] = d
["l2_read_bytes"] / sint
416 def sighandler(*args
):
432 signal(SIGINT
, sighandler
)
446 i
= 0 if i
== hdr_intr
else i
+ 1
453 if __name__
== '__main__':