]> git.proxmox.com Git - mirror_zfs-debian.git/blame - cmd/arc_summary/arc_summary.py
New upstream version 0.7.5
[mirror_zfs-debian.git] / cmd / arc_summary / arc_summary.py
CommitLineData
ea04106b
AX
1#!/usr/bin/python
2#
3# $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $
4#
5# Copyright (c) 2008 Ben Rockwood <benr@cuddletech.com>,
6# Copyright (c) 2010 Martin Matuska <mm@FreeBSD.org>,
7# Copyright (c) 2010-2011 Jason J. Hellenthal <jhell@DataIX.net>,
8# All rights reserved.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions
12# are met:
13#
14# 1. Redistributions of source code must retain the above copyright
15# notice, this list of conditions and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright
17# notice, this list of conditions and the following disclaimer in the
18# documentation and/or other materials provided with the distribution.
19#
20# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30# SUCH DAMAGE.
31#
32# If you are having troubles when using this script from cron(8) please try
33# adjusting your PATH before reporting problems.
34#
35# /usr/bin & /sbin
36#
37# Binaries used are:
38#
39# dc(1), kldstat(8), sed(1), sysctl(8) & vmstat(8)
40#
41# Binaries that I am working on phasing out are:
42#
43# dc(1) & sed(1)
44
45import sys
46import time
47import getopt
48import re
49from os import listdir
50from subprocess import Popen, PIPE
51from decimal import Decimal as D
52
53
54usetunable = True
55show_tunable_descriptions = False
56alternate_tunable_layout = False
57kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M)
58
59
60def get_Kstat():
61 def load_proc_kstats(fn, namespace):
62 kstats = [line.strip() for line in open(fn)]
63 del kstats[0:2]
64 for kstat in kstats:
65 kstat = kstat.strip()
66 name, unused, value = kstat.split()
67 Kstat[namespace + name] = D(value)
68
ea04106b
AX
69 Kstat = {}
70 load_proc_kstats('/proc/spl/kstat/zfs/arcstats',
cae5b340 71 'kstat.zfs.misc.arcstats.')
ea04106b 72 load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats',
cae5b340 73 'kstat.zfs.misc.zfetchstats.')
ea04106b 74 load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats',
cae5b340 75 'kstat.zfs.misc.vdev_cache_stats.')
ea04106b
AX
76
77 return Kstat
78
cae5b340 79
ea04106b
AX
80def div1():
81 sys.stdout.write("\n")
4d815aed 82 for i in range(18):
ea04106b
AX
83 sys.stdout.write("%s" % "----")
84 sys.stdout.write("\n")
85
86
87def div2():
88 sys.stdout.write("\n")
89
90
91def fBytes(Bytes=0, Decimal=2):
92 kbytes = (2 ** 10)
93 mbytes = (2 ** 20)
94 gbytes = (2 ** 30)
95 tbytes = (2 ** 40)
96 pbytes = (2 ** 50)
97 ebytes = (2 ** 60)
98 zbytes = (2 ** 70)
99 ybytes = (2 ** 80)
100
101 if Bytes >= ybytes:
102 return str("%0." + str(Decimal) + "f") % (Bytes / ybytes) + "\tYiB"
103 elif Bytes >= zbytes:
104 return str("%0." + str(Decimal) + "f") % (Bytes / zbytes) + "\tZiB"
105 elif Bytes >= ebytes:
106 return str("%0." + str(Decimal) + "f") % (Bytes / ebytes) + "\tEiB"
107 elif Bytes >= pbytes:
108 return str("%0." + str(Decimal) + "f") % (Bytes / pbytes) + "\tPiB"
109 elif Bytes >= tbytes:
110 return str("%0." + str(Decimal) + "f") % (Bytes / tbytes) + "\tTiB"
111 elif Bytes >= gbytes:
112 return str("%0." + str(Decimal) + "f") % (Bytes / gbytes) + "\tGiB"
113 elif Bytes >= mbytes:
114 return str("%0." + str(Decimal) + "f") % (Bytes / mbytes) + "\tMiB"
115 elif Bytes >= kbytes:
116 return str("%0." + str(Decimal) + "f") % (Bytes / kbytes) + "\tKiB"
117 elif Bytes == 0:
118 return str("%d" % 0) + "\tBytes"
119 else:
120 return str("%d" % Bytes) + "\tBytes"
121
122
123def fHits(Hits=0, Decimal=2):
124 khits = (10 ** 3)
125 mhits = (10 ** 6)
126 bhits = (10 ** 9)
127 thits = (10 ** 12)
128 qhits = (10 ** 15)
129 Qhits = (10 ** 18)
130 shits = (10 ** 21)
131 Shits = (10 ** 24)
132
133 if Hits >= Shits:
134 return str("%0." + str(Decimal) + "f") % (Hits / Shits) + "S"
135 elif Hits >= shits:
136 return str("%0." + str(Decimal) + "f") % (Hits / shits) + "s"
137 elif Hits >= Qhits:
138 return str("%0." + str(Decimal) + "f") % (Hits / Qhits) + "Q"
139 elif Hits >= qhits:
140 return str("%0." + str(Decimal) + "f") % (Hits / qhits) + "q"
141 elif Hits >= thits:
142 return str("%0." + str(Decimal) + "f") % (Hits / thits) + "t"
143 elif Hits >= bhits:
144 return str("%0." + str(Decimal) + "f") % (Hits / bhits) + "b"
145 elif Hits >= mhits:
146 return str("%0." + str(Decimal) + "f") % (Hits / mhits) + "m"
147 elif Hits >= khits:
148 return str("%0." + str(Decimal) + "f") % (Hits / khits) + "k"
149 elif Hits == 0:
150 return str("%d" % 0)
151 else:
152 return str("%d" % Hits)
153
154
155def fPerc(lVal=0, rVal=0, Decimal=2):
156 if rVal > 0:
157 return str("%0." + str(Decimal) + "f") % (100 * (lVal / rVal)) + "%"
158 else:
159 return str("%0." + str(Decimal) + "f") % 100 + "%"
160
161
162def get_arc_summary(Kstat):
163
164 output = {}
165 memory_throttle_count = Kstat[
166 "kstat.zfs.misc.arcstats.memory_throttle_count"
167 ]
168
169 if memory_throttle_count > 0:
170 output['health'] = 'THROTTLED'
171 else:
172 output['health'] = 'HEALTHY'
173
174 output['memory_throttle_count'] = fHits(memory_throttle_count)
175
cae5b340 176 # ARC Misc.
ea04106b
AX
177 deleted = Kstat["kstat.zfs.misc.arcstats.deleted"]
178 mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"]
ea04106b 179
cae5b340 180 # ARC Misc.
ea04106b
AX
181 output["arc_misc"] = {}
182 output["arc_misc"]["deleted"] = fHits(deleted)
ea04106b
AX
183 output["arc_misc"]['mutex_miss'] = fHits(mutex_miss)
184 output["arc_misc"]['evict_skips'] = fHits(mutex_miss)
185
cae5b340 186 # ARC Sizing
ea04106b 187 arc_size = Kstat["kstat.zfs.misc.arcstats.size"]
41d74433
AX
188 mru_size = Kstat["kstat.zfs.misc.arcstats.mru_size"]
189 mfu_size = Kstat["kstat.zfs.misc.arcstats.mfu_size"]
ea04106b
AX
190 target_max_size = Kstat["kstat.zfs.misc.arcstats.c_max"]
191 target_min_size = Kstat["kstat.zfs.misc.arcstats.c_min"]
192 target_size = Kstat["kstat.zfs.misc.arcstats.c"]
193
194 target_size_ratio = (target_max_size / target_min_size)
195
cae5b340 196 # ARC Sizing
ea04106b
AX
197 output['arc_sizing'] = {}
198 output['arc_sizing']['arc_size'] = {
199 'per': fPerc(arc_size, target_max_size),
200 'num': fBytes(arc_size),
201 }
202 output['arc_sizing']['target_max_size'] = {
203 'ratio': target_size_ratio,
204 'num': fBytes(target_max_size),
205 }
206 output['arc_sizing']['target_min_size'] = {
207 'per': fPerc(target_min_size, target_max_size),
208 'num': fBytes(target_min_size),
209 }
210 output['arc_sizing']['target_size'] = {
211 'per': fPerc(target_size, target_max_size),
212 'num': fBytes(target_size),
213 }
214
cae5b340 215 # ARC Hash Breakdown
ea04106b
AX
216 output['arc_hash_break'] = {}
217 output['arc_hash_break']['hash_chain_max'] = Kstat[
218 "kstat.zfs.misc.arcstats.hash_chain_max"
219 ]
220 output['arc_hash_break']['hash_chains'] = Kstat[
221 "kstat.zfs.misc.arcstats.hash_chains"
222 ]
223 output['arc_hash_break']['hash_collisions'] = Kstat[
224 "kstat.zfs.misc.arcstats.hash_collisions"
225 ]
226 output['arc_hash_break']['hash_elements'] = Kstat[
227 "kstat.zfs.misc.arcstats.hash_elements"
228 ]
229 output['arc_hash_break']['hash_elements_max'] = Kstat[
230 "kstat.zfs.misc.arcstats.hash_elements_max"
231 ]
232
233 output['arc_size_break'] = {}
41d74433
AX
234 output['arc_size_break']['recently_used_cache_size'] = {
235 'per': fPerc(mru_size, mru_size + mfu_size),
236 'num': fBytes(mru_size),
237 }
238 output['arc_size_break']['frequently_used_cache_size'] = {
239 'per': fPerc(mfu_size, mru_size + mfu_size),
240 'num': fBytes(mfu_size),
241 }
ea04106b 242
cae5b340 243 # ARC Hash Breakdown
ea04106b
AX
244 hash_chain_max = Kstat["kstat.zfs.misc.arcstats.hash_chain_max"]
245 hash_chains = Kstat["kstat.zfs.misc.arcstats.hash_chains"]
246 hash_collisions = Kstat["kstat.zfs.misc.arcstats.hash_collisions"]
247 hash_elements = Kstat["kstat.zfs.misc.arcstats.hash_elements"]
248 hash_elements_max = Kstat["kstat.zfs.misc.arcstats.hash_elements_max"]
249
250 output['arc_hash_break'] = {}
251 output['arc_hash_break']['elements_max'] = fHits(hash_elements_max)
252 output['arc_hash_break']['elements_current'] = {
253 'per': fPerc(hash_elements, hash_elements_max),
254 'num': fHits(hash_elements),
255 }
256 output['arc_hash_break']['collisions'] = fHits(hash_collisions)
257 output['arc_hash_break']['chain_max'] = fHits(hash_chain_max)
258 output['arc_hash_break']['chains'] = fHits(hash_chains)
259
260 return output
261
262
263def _arc_summary(Kstat):
cae5b340 264 # ARC Sizing
ea04106b
AX
265 arc = get_arc_summary(Kstat)
266
267 sys.stdout.write("ARC Summary: (%s)\n" % arc['health'])
268
269 sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" %
cae5b340 270 arc['memory_throttle_count'])
ea04106b
AX
271 sys.stdout.write("\n")
272
cae5b340 273 # ARC Misc.
ea04106b
AX
274 sys.stdout.write("ARC Misc:\n")
275 sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted'])
ea04106b 276 sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" %
cae5b340 277 arc['arc_misc']['mutex_miss'])
ea04106b 278 sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" %
cae5b340 279 arc['arc_misc']['mutex_miss'])
ea04106b
AX
280 sys.stdout.write("\n")
281
cae5b340 282 # ARC Sizing
ea04106b
AX
283 sys.stdout.write("ARC Size:\t\t\t\t%s\t%s\n" % (
284 arc['arc_sizing']['arc_size']['per'],
285 arc['arc_sizing']['arc_size']['num']
286 )
287 )
288 sys.stdout.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % (
289 arc['arc_sizing']['target_size']['per'],
290 arc['arc_sizing']['target_size']['num'],
291 )
292 )
293
294 sys.stdout.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % (
295 arc['arc_sizing']['target_min_size']['per'],
296 arc['arc_sizing']['target_min_size']['num'],
297 )
298 )
299
300 sys.stdout.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % (
301 arc['arc_sizing']['target_max_size']['ratio'],
302 arc['arc_sizing']['target_max_size']['num'],
303 )
304 )
305
306 sys.stdout.write("\nARC Size Breakdown:\n")
307 sys.stdout.write("\tRecently Used Cache Size:\t%s\t%s\n" % (
308 arc['arc_size_break']['recently_used_cache_size']['per'],
309 arc['arc_size_break']['recently_used_cache_size']['num'],
310 )
311 )
312 sys.stdout.write("\tFrequently Used Cache Size:\t%s\t%s\n" % (
313 arc['arc_size_break']['frequently_used_cache_size']['per'],
314 arc['arc_size_break']['frequently_used_cache_size']['num'],
315 )
316 )
317
318 sys.stdout.write("\n")
319
cae5b340 320 # ARC Hash Breakdown
ea04106b
AX
321 sys.stdout.write("ARC Hash Breakdown:\n")
322 sys.stdout.write("\tElements Max:\t\t\t\t%s\n" %
cae5b340 323 arc['arc_hash_break']['elements_max'])
ea04106b
AX
324 sys.stdout.write("\tElements Current:\t\t%s\t%s\n" % (
325 arc['arc_hash_break']['elements_current']['per'],
326 arc['arc_hash_break']['elements_current']['num'],
327 )
328 )
329 sys.stdout.write("\tCollisions:\t\t\t\t%s\n" %
cae5b340 330 arc['arc_hash_break']['collisions'])
ea04106b 331 sys.stdout.write("\tChain Max:\t\t\t\t%s\n" %
cae5b340 332 arc['arc_hash_break']['chain_max'])
ea04106b 333 sys.stdout.write("\tChains:\t\t\t\t\t%s\n" %
cae5b340 334 arc['arc_hash_break']['chains'])
ea04106b
AX
335
336
337def get_arc_efficiency(Kstat):
338 output = {}
339
340 arc_hits = Kstat["kstat.zfs.misc.arcstats.hits"]
341 arc_misses = Kstat["kstat.zfs.misc.arcstats.misses"]
342 demand_data_hits = Kstat["kstat.zfs.misc.arcstats.demand_data_hits"]
343 demand_data_misses = Kstat["kstat.zfs.misc.arcstats.demand_data_misses"]
344 demand_metadata_hits = Kstat[
345 "kstat.zfs.misc.arcstats.demand_metadata_hits"
346 ]
347 demand_metadata_misses = Kstat[
348 "kstat.zfs.misc.arcstats.demand_metadata_misses"
349 ]
350 mfu_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mfu_ghost_hits"]
351 mfu_hits = Kstat["kstat.zfs.misc.arcstats.mfu_hits"]
352 mru_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mru_ghost_hits"]
353 mru_hits = Kstat["kstat.zfs.misc.arcstats.mru_hits"]
354 prefetch_data_hits = Kstat["kstat.zfs.misc.arcstats.prefetch_data_hits"]
355 prefetch_data_misses = Kstat[
356 "kstat.zfs.misc.arcstats.prefetch_data_misses"
357 ]
358 prefetch_metadata_hits = Kstat[
359 "kstat.zfs.misc.arcstats.prefetch_metadata_hits"
360 ]
361 prefetch_metadata_misses = Kstat[
362 "kstat.zfs.misc.arcstats.prefetch_metadata_misses"
363 ]
364
365 anon_hits = arc_hits - (
366 mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits
367 )
368 arc_accesses_total = (arc_hits + arc_misses)
369 demand_data_total = (demand_data_hits + demand_data_misses)
370 prefetch_data_total = (prefetch_data_hits + prefetch_data_misses)
371 real_hits = (mfu_hits + mru_hits)
372
373 output["total_accesses"] = fHits(arc_accesses_total)
374 output["cache_hit_ratio"] = {
375 'per': fPerc(arc_hits, arc_accesses_total),
376 'num': fHits(arc_hits),
377 }
378 output["cache_miss_ratio"] = {
379 'per': fPerc(arc_misses, arc_accesses_total),
380 'num': fHits(arc_misses),
381 }
382 output["actual_hit_ratio"] = {
383 'per': fPerc(real_hits, arc_accesses_total),
384 'num': fHits(real_hits),
385 }
386 output["data_demand_efficiency"] = {
387 'per': fPerc(demand_data_hits, demand_data_total),
388 'num': fHits(demand_data_total),
389 }
390
391 if prefetch_data_total > 0:
392 output["data_prefetch_efficiency"] = {
393 'per': fPerc(prefetch_data_hits, prefetch_data_total),
394 'num': fHits(prefetch_data_total),
395 }
396
397 if anon_hits > 0:
398 output["cache_hits_by_cache_list"] = {}
399 output["cache_hits_by_cache_list"]["anonymously_used"] = {
400 'per': fPerc(anon_hits, arc_hits),
401 'num': fHits(anon_hits),
402 }
403
404 output["most_recently_used"] = {
405 'per': fPerc(mru_hits, arc_hits),
406 'num': fHits(mru_hits),
407 }
408 output["most_frequently_used"] = {
409 'per': fPerc(mfu_hits, arc_hits),
410 'num': fHits(mfu_hits),
411 }
412 output["most_recently_used_ghost"] = {
413 'per': fPerc(mru_ghost_hits, arc_hits),
414 'num': fHits(mru_ghost_hits),
415 }
416 output["most_frequently_used_ghost"] = {
417 'per': fPerc(mfu_ghost_hits, arc_hits),
418 'num': fHits(mfu_ghost_hits),
419 }
420
421 output["cache_hits_by_data_type"] = {}
422 output["cache_hits_by_data_type"]["demand_data"] = {
423 'per': fPerc(demand_data_hits, arc_hits),
424 'num': fHits(demand_data_hits),
425 }
426 output["cache_hits_by_data_type"]["prefetch_data"] = {
427 'per': fPerc(prefetch_data_hits, arc_hits),
428 'num': fHits(prefetch_data_hits),
429 }
430 output["cache_hits_by_data_type"]["demand_metadata"] = {
431 'per': fPerc(demand_metadata_hits, arc_hits),
432 'num': fHits(demand_metadata_hits),
433 }
434 output["cache_hits_by_data_type"]["prefetch_metadata"] = {
435 'per': fPerc(prefetch_metadata_hits, arc_hits),
436 'num': fHits(prefetch_metadata_hits),
437 }
438
439 output["cache_misses_by_data_type"] = {}
440 output["cache_misses_by_data_type"]["demand_data"] = {
441 'per': fPerc(demand_data_misses, arc_misses),
442 'num': fHits(demand_data_misses),
443 }
444 output["cache_misses_by_data_type"]["prefetch_data"] = {
445 'per': fPerc(prefetch_data_misses, arc_misses),
446 'num': fHits(prefetch_data_misses),
447 }
448 output["cache_misses_by_data_type"]["demand_metadata"] = {
449 'per': fPerc(demand_metadata_misses, arc_misses),
450 'num': fHits(demand_metadata_misses),
451 }
452 output["cache_misses_by_data_type"]["prefetch_metadata"] = {
453 'per': fPerc(prefetch_metadata_misses, arc_misses),
454 'num': fHits(prefetch_metadata_misses),
455 }
456
457 return output
458
459
460def _arc_efficiency(Kstat):
461 arc = get_arc_efficiency(Kstat)
462
463 sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" %
cae5b340 464 arc['total_accesses'])
ea04106b
AX
465 sys.stdout.write("\tCache Hit Ratio:\t\t%s\t%s\n" % (
466 arc['cache_hit_ratio']['per'],
467 arc['cache_hit_ratio']['num'],
468 )
469 )
470 sys.stdout.write("\tCache Miss Ratio:\t\t%s\t%s\n" % (
471 arc['cache_miss_ratio']['per'],
472 arc['cache_miss_ratio']['num'],
473 )
474 )
475
476 sys.stdout.write("\tActual Hit Ratio:\t\t%s\t%s\n" % (
477 arc['actual_hit_ratio']['per'],
478 arc['actual_hit_ratio']['num'],
479 )
480 )
481
482 sys.stdout.write("\n")
483 sys.stdout.write("\tData Demand Efficiency:\t\t%s\t%s\n" % (
484 arc['data_demand_efficiency']['per'],
485 arc['data_demand_efficiency']['num'],
486 )
487 )
488
489 if 'data_prefetch_efficiency' in arc:
490 sys.stdout.write("\tData Prefetch Efficiency:\t%s\t%s\n" % (
491 arc['data_prefetch_efficiency']['per'],
492 arc['data_prefetch_efficiency']['num'],
493 )
494 )
495 sys.stdout.write("\n")
496
497 sys.stdout.write("\tCACHE HITS BY CACHE LIST:\n")
498 if 'cache_hits_by_cache_list' in arc:
499 sys.stdout.write("\t Anonymously Used:\t\t%s\t%s\n" % (
500 arc['cache_hits_by_cache_list']['anonymously_used']['per'],
501 arc['cache_hits_by_cache_list']['anonymously_used']['num'],
502 )
503 )
504 sys.stdout.write("\t Most Recently Used:\t\t%s\t%s\n" % (
505 arc['most_recently_used']['per'],
506 arc['most_recently_used']['num'],
507 )
508 )
509 sys.stdout.write("\t Most Frequently Used:\t\t%s\t%s\n" % (
510 arc['most_frequently_used']['per'],
511 arc['most_frequently_used']['num'],
512 )
513 )
514 sys.stdout.write("\t Most Recently Used Ghost:\t%s\t%s\n" % (
515 arc['most_recently_used_ghost']['per'],
516 arc['most_recently_used_ghost']['num'],
517 )
518 )
519 sys.stdout.write("\t Most Frequently Used Ghost:\t%s\t%s\n" % (
520 arc['most_frequently_used_ghost']['per'],
521 arc['most_frequently_used_ghost']['num'],
522 )
523 )
524
525 sys.stdout.write("\n\tCACHE HITS BY DATA TYPE:\n")
526 sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % (
527 arc["cache_hits_by_data_type"]['demand_data']['per'],
528 arc["cache_hits_by_data_type"]['demand_data']['num'],
529 )
530 )
531 sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % (
532 arc["cache_hits_by_data_type"]['prefetch_data']['per'],
533 arc["cache_hits_by_data_type"]['prefetch_data']['num'],
534 )
535 )
536 sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % (
537 arc["cache_hits_by_data_type"]['demand_metadata']['per'],
538 arc["cache_hits_by_data_type"]['demand_metadata']['num'],
539 )
540 )
541 sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
542 arc["cache_hits_by_data_type"]['prefetch_metadata']['per'],
543 arc["cache_hits_by_data_type"]['prefetch_metadata']['num'],
544 )
545 )
546
547 sys.stdout.write("\n\tCACHE MISSES BY DATA TYPE:\n")
548 sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % (
549 arc["cache_misses_by_data_type"]['demand_data']['per'],
550 arc["cache_misses_by_data_type"]['demand_data']['num'],
551 )
552 )
553 sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % (
554 arc["cache_misses_by_data_type"]['prefetch_data']['per'],
555 arc["cache_misses_by_data_type"]['prefetch_data']['num'],
556 )
557 )
558 sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % (
559 arc["cache_misses_by_data_type"]['demand_metadata']['per'],
560 arc["cache_misses_by_data_type"]['demand_metadata']['num'],
561 )
562 )
563 sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
564 arc["cache_misses_by_data_type"]['prefetch_metadata']['per'],
565 arc["cache_misses_by_data_type"]['prefetch_metadata']['num'],
566 )
567 )
568
569
570def get_l2arc_summary(Kstat):
571 output = {}
572
573 l2_abort_lowmem = Kstat["kstat.zfs.misc.arcstats.l2_abort_lowmem"]
574 l2_cksum_bad = Kstat["kstat.zfs.misc.arcstats.l2_cksum_bad"]
575 l2_evict_lock_retry = Kstat["kstat.zfs.misc.arcstats.l2_evict_lock_retry"]
576 l2_evict_reading = Kstat["kstat.zfs.misc.arcstats.l2_evict_reading"]
577 l2_feeds = Kstat["kstat.zfs.misc.arcstats.l2_feeds"]
578 l2_free_on_write = Kstat["kstat.zfs.misc.arcstats.l2_free_on_write"]
579 l2_hdr_size = Kstat["kstat.zfs.misc.arcstats.l2_hdr_size"]
580 l2_hits = Kstat["kstat.zfs.misc.arcstats.l2_hits"]
581 l2_io_error = Kstat["kstat.zfs.misc.arcstats.l2_io_error"]
582 l2_misses = Kstat["kstat.zfs.misc.arcstats.l2_misses"]
583 l2_rw_clash = Kstat["kstat.zfs.misc.arcstats.l2_rw_clash"]
584 l2_size = Kstat["kstat.zfs.misc.arcstats.l2_size"]
585 l2_asize = Kstat["kstat.zfs.misc.arcstats.l2_asize"]
586 l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"]
587 l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"]
588 l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"]
589
590 l2_access_total = (l2_hits + l2_misses)
591 output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error)
592
593 output['l2_access_total'] = l2_access_total
594 output['l2_size'] = l2_size
595 output['l2_asize'] = l2_asize
596
597 if l2_size > 0 and l2_access_total > 0:
598
599 if output['l2_health_count'] > 0:
600 output["health"] = "DEGRADED"
601 else:
602 output["health"] = "HEALTHY"
603
604 output["low_memory_aborts"] = fHits(l2_abort_lowmem)
605 output["free_on_write"] = fHits(l2_free_on_write)
606 output["rw_clashes"] = fHits(l2_rw_clash)
607 output["bad_checksums"] = fHits(l2_cksum_bad)
608 output["io_errors"] = fHits(l2_io_error)
609
610 output["l2_arc_size"] = {}
611 output["l2_arc_size"]["adative"] = fBytes(l2_size)
612 output["l2_arc_size"]["actual"] = {
613 'per': fPerc(l2_asize, l2_size),
614 'num': fBytes(l2_asize)
615 }
616 output["l2_arc_size"]["head_size"] = {
617 'per': fPerc(l2_hdr_size, l2_size),
618 'num': fBytes(l2_hdr_size),
619 }
620
621 output["l2_arc_evicts"] = {}
622 output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry)
623 output["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading)
624
625 output['l2_arc_breakdown'] = {}
626 output['l2_arc_breakdown']['value'] = fHits(l2_access_total)
627 output['l2_arc_breakdown']['hit_ratio'] = {
628 'per': fPerc(l2_hits, l2_access_total),
629 'num': fHits(l2_hits),
630 }
631 output['l2_arc_breakdown']['miss_ratio'] = {
632 'per': fPerc(l2_misses, l2_access_total),
633 'num': fHits(l2_misses),
634 }
635 output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds)
636
637 output['l2_arc_buffer'] = {}
638
639 output['l2_arc_writes'] = {}
640 output['l2_writes_done'] = l2_writes_done
641 output['l2_writes_sent'] = l2_writes_sent
642 if l2_writes_done != l2_writes_sent:
643 output['l2_arc_writes']['writes_sent'] = {
644 'value': "FAULTED",
645 'num': fHits(l2_writes_sent),
646 }
647 output['l2_arc_writes']['done_ratio'] = {
648 'per': fPerc(l2_writes_done, l2_writes_sent),
649 'num': fHits(l2_writes_done),
650 }
651 output['l2_arc_writes']['error_ratio'] = {
652 'per': fPerc(l2_writes_error, l2_writes_sent),
653 'num': fHits(l2_writes_error),
654 }
655 else:
656 output['l2_arc_writes']['writes_sent'] = {
657 'per': fPerc(100),
658 'num': fHits(l2_writes_sent),
659 }
660
661 return output
662
663
664def _l2arc_summary(Kstat):
665
666 arc = get_l2arc_summary(Kstat)
667
668 if arc['l2_size'] > 0 and arc['l2_access_total'] > 0:
669 sys.stdout.write("L2 ARC Summary: ")
670 if arc['l2_health_count'] > 0:
671 sys.stdout.write("(DEGRADED)\n")
672 else:
673 sys.stdout.write("(HEALTHY)\n")
674 sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" %
cae5b340 675 arc['low_memory_aborts'])
ea04106b
AX
676 sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write'])
677 sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes'])
678 sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums'])
679 sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors'])
680 sys.stdout.write("\n")
681
682 sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
cae5b340 683 arc["l2_arc_size"]["adative"])
ea04106b
AX
684 sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % (
685 arc["l2_arc_size"]["actual"]["per"],
686 arc["l2_arc_size"]["actual"]["num"],
687 )
688 )
689 sys.stdout.write("\tHeader Size:\t\t\t%s\t%s\n" % (
690 arc["l2_arc_size"]["head_size"]["per"],
691 arc["l2_arc_size"]["head_size"]["num"],
692 )
693 )
694 sys.stdout.write("\n")
695
cae5b340
AX
696 if arc["l2_arc_evicts"]['lock_retries'] != '0' or \
697 arc["l2_arc_evicts"]["reading"] != '0':
ea04106b
AX
698 sys.stdout.write("L2 ARC Evicts:\n")
699 sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" %
cae5b340 700 arc["l2_arc_evicts"]['lock_retries'])
ea04106b 701 sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" %
cae5b340 702 arc["l2_arc_evicts"]["reading"])
ea04106b
AX
703 sys.stdout.write("\n")
704
705 sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" %
cae5b340 706 arc['l2_arc_breakdown']['value'])
ea04106b
AX
707 sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
708 arc['l2_arc_breakdown']['hit_ratio']['per'],
709 arc['l2_arc_breakdown']['hit_ratio']['num'],
710 )
711 )
712
713 sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
714 arc['l2_arc_breakdown']['miss_ratio']['per'],
715 arc['l2_arc_breakdown']['miss_ratio']['num'],
716 )
717 )
718
719 sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" %
cae5b340 720 arc['l2_arc_breakdown']['feeds'])
ea04106b
AX
721 sys.stdout.write("\n")
722
723 sys.stdout.write("L2 ARC Writes:\n")
724 if arc['l2_writes_done'] != arc['l2_writes_sent']:
725 sys.stdout.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % (
726 arc['l2_arc_writes']['writes_sent']['value'],
727 arc['l2_arc_writes']['writes_sent']['num'],
728 )
729 )
730 sys.stdout.write("\t Done Ratio:\t\t\t%s\t%s\n" % (
731 arc['l2_arc_writes']['done_ratio']['per'],
732 arc['l2_arc_writes']['done_ratio']['num'],
733 )
734 )
735 sys.stdout.write("\t Error Ratio:\t\t\t%s\t%s\n" % (
736 arc['l2_arc_writes']['error_ratio']['per'],
737 arc['l2_arc_writes']['error_ratio']['num'],
738 )
739 )
740 else:
741 sys.stdout.write("\tWrites Sent:\t\t\t%s\t%s\n" % (
742 arc['l2_arc_writes']['writes_sent']['per'],
743 arc['l2_arc_writes']['writes_sent']['num'],
744 )
745 )
746
747
748def get_dmu_summary(Kstat):
749 output = {}
750
ea04106b
AX
751 zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"]
752 zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"]
ea04106b
AX
753
754 zfetch_access_total = (zfetch_hits + zfetch_misses)
ea04106b
AX
755 output['zfetch_access_total'] = zfetch_access_total
756
757 if zfetch_access_total > 0:
ea04106b
AX
758 output['dmu'] = {}
759 output['dmu']['efficiency'] = {}
760 output['dmu']['efficiency']['value'] = fHits(zfetch_access_total)
761 output['dmu']['efficiency']['hit_ratio'] = {
762 'per': fPerc(zfetch_hits, zfetch_access_total),
763 'num': fHits(zfetch_hits),
764 }
765 output['dmu']['efficiency']['miss_ratio'] = {
766 'per': fPerc(zfetch_misses, zfetch_access_total),
767 'num': fHits(zfetch_misses),
768 }
769
ea04106b
AX
770 return output
771
772
773def _dmu_summary(Kstat):
774
775 arc = get_dmu_summary(Kstat)
776
777 if arc['zfetch_access_total'] > 0:
cae5b340
AX
778 sys.stdout.write("DMU Prefetch Efficiency:\t\t\t\t\t%s\n" %
779 arc['dmu']['efficiency']['value'])
ea04106b
AX
780 sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
781 arc['dmu']['efficiency']['hit_ratio']['per'],
782 arc['dmu']['efficiency']['hit_ratio']['num'],
783 )
784 )
785 sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
786 arc['dmu']['efficiency']['miss_ratio']['per'],
787 arc['dmu']['efficiency']['miss_ratio']['num'],
788 )
789 )
790
791 sys.stdout.write("\n")
792
ea04106b
AX
793
794def get_vdev_summary(Kstat):
795 output = {}
796
797 vdev_cache_delegations = \
cae5b340 798 Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"]
ea04106b
AX
799 vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"]
800 vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"]
801 vdev_cache_total = (vdev_cache_misses + vdev_cache_hits +
cae5b340 802 vdev_cache_delegations)
ea04106b
AX
803
804 output['vdev_cache_total'] = vdev_cache_total
805
806 if vdev_cache_total > 0:
807 output['summary'] = fHits(vdev_cache_total)
808 output['hit_ratio'] = {
809 'per': fPerc(vdev_cache_hits, vdev_cache_total),
810 'num': fHits(vdev_cache_hits),
811 }
812 output['miss_ratio'] = {
813 'per': fPerc(vdev_cache_misses, vdev_cache_total),
814 'num': fHits(vdev_cache_misses),
815 }
816 output['delegations'] = {
817 'per': fPerc(vdev_cache_delegations, vdev_cache_total),
818 'num': fHits(vdev_cache_delegations),
819 }
820
821 return output
822
823
824def _vdev_summary(Kstat):
825 arc = get_vdev_summary(Kstat)
826
827 if arc['vdev_cache_total'] > 0:
828 sys.stdout.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc['summary'])
829 sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
830 arc['hit_ratio']['per'],
831 arc['hit_ratio']['num'],
832 ))
833 sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
834 arc['miss_ratio']['per'],
835 arc['miss_ratio']['num'],
836 ))
837 sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % (
838 arc['delegations']['per'],
839 arc['delegations']['num'],
840 ))
841
842
843def _tunable_summary(Kstat):
844 global show_tunable_descriptions
845 global alternate_tunable_layout
846
847 names = listdir("/sys/module/zfs/parameters/")
848
849 values = {}
850 for name in names:
cae5b340
AX
851 with open("/sys/module/zfs/parameters/" + name) as f:
852 value = f.read()
ea04106b
AX
853 values[name] = value.strip()
854
855 descriptions = {}
856
857 if show_tunable_descriptions:
858 try:
859 command = ["/sbin/modinfo", "zfs", "-0"]
860 p = Popen(command, stdin=PIPE, stdout=PIPE,
cae5b340 861 stderr=PIPE, shell=False, close_fds=True)
ea04106b
AX
862 p.wait()
863
864 description_list = p.communicate()[0].strip().split('\0')
865
866 if p.returncode == 0:
867 for tunable in description_list:
868 if tunable[0:5] == 'parm:':
869 tunable = tunable[5:].strip()
870 name, description = tunable.split(':', 1)
871 if not description:
872 description = "Description unavailable"
873 descriptions[name] = description
874 else:
875 sys.stderr.write("%s: '%s' exited with code %i\n" %
cae5b340 876 (sys.argv[0], command[0], p.returncode))
ea04106b
AX
877 sys.stderr.write("Tunable descriptions will be disabled.\n")
878 except OSError as e:
879 sys.stderr.write("%s: Cannot run '%s': %s\n" %
cae5b340 880 (sys.argv[0], command[0], e.strerror))
ea04106b
AX
881 sys.stderr.write("Tunable descriptions will be disabled.\n")
882
883 sys.stdout.write("ZFS Tunable:\n")
884 for name in names:
885 if not name:
886 continue
887
888 format = "\t%-50s%s\n"
889 if alternate_tunable_layout:
890 format = "\t%s=%s\n"
891
4d815aed 892 if show_tunable_descriptions and name in descriptions:
ea04106b
AX
893 sys.stdout.write("\t# %s\n" % descriptions[name])
894
895 sys.stdout.write(format % (name, values[name]))
896
897
898unSub = [
899 _arc_summary,
900 _arc_efficiency,
901 _l2arc_summary,
902 _dmu_summary,
903 _vdev_summary,
904 _tunable_summary
905]
906
907
908def zfs_header():
909 daydate = time.strftime("%a %b %d %H:%M:%S %Y")
910
911 div1()
912 sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate)
913 div2()
914
915
916def usage():
917 sys.stdout.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n")
918 sys.stdout.write("\t -h, --help : "
cae5b340 919 "Print this help message and exit\n")
ea04106b 920 sys.stdout.write("\t -a, --alternate : "
cae5b340 921 "Show an alternate sysctl layout\n")
ea04106b 922 sys.stdout.write("\t -d, --description : "
cae5b340 923 "Show the sysctl descriptions\n")
ea04106b 924 sys.stdout.write("\t -p PAGE, --page=PAGE : "
cae5b340 925 "Select a single output page to display,\n")
ea04106b 926 sys.stdout.write("\t "
cae5b340
AX
927 "should be an integer between 1 and " +
928 str(len(unSub)) + "\n\n")
ea04106b
AX
929 sys.stdout.write("Examples:\n")
930 sys.stdout.write("\tarc_summary.py -a\n")
931 sys.stdout.write("\tarc_summary.py -p 4\n")
932 sys.stdout.write("\tarc_summary.py -ad\n")
933 sys.stdout.write("\tarc_summary.py --page=2\n")
934
cae5b340 935
ea04106b
AX
936def main():
937 global show_tunable_descriptions
938 global alternate_tunable_layout
939
940 opts, args = getopt.getopt(
941 sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"]
942 )
943
944 args = {}
945 for opt, arg in opts:
946 if opt in ('-a', '--alternate'):
947 args['a'] = True
948 if opt in ('-d', '--description'):
949 args['d'] = True
950 if opt in ('-p', '--page'):
951 args['p'] = arg
952 if opt in ('-h', '--help'):
953 usage()
954 sys.exit()
955
956 Kstat = get_Kstat()
957
958 alternate_tunable_layout = 'a' in args
959 show_tunable_descriptions = 'd' in args
960
961 pages = []
962
963 if 'p' in args:
964 try:
965 pages.append(unSub[int(args['p']) - 1])
cae5b340 966 except IndexError:
ea04106b 967 sys.stderr.write('the argument to -p must be between 1 and ' +
cae5b340 968 str(len(unSub)) + '\n')
ea04106b
AX
969 sys.exit()
970 else:
971 pages = unSub
972
973 zfs_header()
974 for page in pages:
975 page(Kstat)
976 div2()
977
cae5b340 978
ea04106b
AX
979if __name__ == '__main__':
980 main()