3 # $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $
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>,
10 # Redistribution and use in source and binary forms, with or without
11 # modification, are permitted provided that the following conditions
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.
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
32 # If you are having troubles when using this script from cron(8) please try
33 # adjusting your PATH before reporting problems.
39 # dc(1), kldstat(8), sed(1), sysctl(8) & vmstat(8)
41 # Binaries that I am working on phasing out are:
49 from os
import listdir
50 from subprocess
import Popen
, PIPE
51 from decimal
import Decimal
as D
55 show_tunable_descriptions
= False
56 alternate_tunable_layout
= False
57 kstat_pobj
= re
.compile("^([^:]+):\s+(.+)\s*$", flags
=re
.M
)
61 def load_proc_kstats(fn
, namespace
):
62 kstats
= [line
.strip() for line
in open(fn
)]
66 name
, unused
, value
= kstat
.split()
67 Kstat
[namespace
+ name
] = D(value
)
86 load_proc_kstats('/proc/spl/kstat/zfs/arcstats',
87 'kstat.zfs.misc.arcstats.')
88 load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats',
89 'kstat.zfs.misc.zfetchstats.')
90 load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats',
91 'kstat.zfs.misc.vdev_cache_stats.')
96 sys
.stdout
.write("\n")
98 sys
.stdout
.write("%s" % "----")
99 sys
.stdout
.write("\n")
103 sys
.stdout
.write("\n")
106 def fBytes(Bytes
=0, Decimal
=2):
117 return str("%0." + str(Decimal
) + "f") % (Bytes
/ ybytes
) + "\tYiB"
118 elif Bytes
>= zbytes
:
119 return str("%0." + str(Decimal
) + "f") % (Bytes
/ zbytes
) + "\tZiB"
120 elif Bytes
>= ebytes
:
121 return str("%0." + str(Decimal
) + "f") % (Bytes
/ ebytes
) + "\tEiB"
122 elif Bytes
>= pbytes
:
123 return str("%0." + str(Decimal
) + "f") % (Bytes
/ pbytes
) + "\tPiB"
124 elif Bytes
>= tbytes
:
125 return str("%0." + str(Decimal
) + "f") % (Bytes
/ tbytes
) + "\tTiB"
126 elif Bytes
>= gbytes
:
127 return str("%0." + str(Decimal
) + "f") % (Bytes
/ gbytes
) + "\tGiB"
128 elif Bytes
>= mbytes
:
129 return str("%0." + str(Decimal
) + "f") % (Bytes
/ mbytes
) + "\tMiB"
130 elif Bytes
>= kbytes
:
131 return str("%0." + str(Decimal
) + "f") % (Bytes
/ kbytes
) + "\tKiB"
133 return str("%d" % 0) + "\tBytes"
135 return str("%d" % Bytes
) + "\tBytes"
138 def fHits(Hits
=0, Decimal
=2):
149 return str("%0." + str(Decimal
) + "f") % (Hits
/ Shits
) + "S"
151 return str("%0." + str(Decimal
) + "f") % (Hits
/ shits
) + "s"
153 return str("%0." + str(Decimal
) + "f") % (Hits
/ Qhits
) + "Q"
155 return str("%0." + str(Decimal
) + "f") % (Hits
/ qhits
) + "q"
157 return str("%0." + str(Decimal
) + "f") % (Hits
/ thits
) + "t"
159 return str("%0." + str(Decimal
) + "f") % (Hits
/ bhits
) + "b"
161 return str("%0." + str(Decimal
) + "f") % (Hits
/ mhits
) + "m"
163 return str("%0." + str(Decimal
) + "f") % (Hits
/ khits
) + "k"
167 return str("%d" % Hits
)
170 def fPerc(lVal
=0, rVal
=0, Decimal
=2):
172 return str("%0." + str(Decimal
) + "f") % (100 * (lVal
/ rVal
)) + "%"
174 return str("%0." + str(Decimal
) + "f") % 100 + "%"
177 def get_arc_summary(Kstat
):
180 memory_throttle_count
= Kstat
[
181 "kstat.zfs.misc.arcstats.memory_throttle_count"
184 if memory_throttle_count
> 0:
185 output
['health'] = 'THROTTLED'
187 output
['health'] = 'HEALTHY'
189 output
['memory_throttle_count'] = fHits(memory_throttle_count
)
192 deleted
= Kstat
["kstat.zfs.misc.arcstats.deleted"]
193 mutex_miss
= Kstat
["kstat.zfs.misc.arcstats.mutex_miss"]
196 output
["arc_misc"] = {}
197 output
["arc_misc"]["deleted"] = fHits(deleted
)
198 output
["arc_misc"]['mutex_miss'] = fHits(mutex_miss
)
199 output
["arc_misc"]['evict_skips'] = fHits(mutex_miss
)
202 arc_size
= Kstat
["kstat.zfs.misc.arcstats.size"]
203 mru_size
= Kstat
["kstat.zfs.misc.arcstats.p"]
204 target_max_size
= Kstat
["kstat.zfs.misc.arcstats.c_max"]
205 target_min_size
= Kstat
["kstat.zfs.misc.arcstats.c_min"]
206 target_size
= Kstat
["kstat.zfs.misc.arcstats.c"]
208 target_size_ratio
= (target_max_size
/ target_min_size
)
211 output
['arc_sizing'] = {}
212 output
['arc_sizing']['arc_size'] = {
213 'per': fPerc(arc_size
, target_max_size
),
214 'num': fBytes(arc_size
),
216 output
['arc_sizing']['target_max_size'] = {
217 'ratio': target_size_ratio
,
218 'num': fBytes(target_max_size
),
220 output
['arc_sizing']['target_min_size'] = {
221 'per': fPerc(target_min_size
, target_max_size
),
222 'num': fBytes(target_min_size
),
224 output
['arc_sizing']['target_size'] = {
225 'per': fPerc(target_size
, target_max_size
),
226 'num': fBytes(target_size
),
229 ### ARC Hash Breakdown ###
230 output
['arc_hash_break'] = {}
231 output
['arc_hash_break']['hash_chain_max'] = Kstat
[
232 "kstat.zfs.misc.arcstats.hash_chain_max"
234 output
['arc_hash_break']['hash_chains'] = Kstat
[
235 "kstat.zfs.misc.arcstats.hash_chains"
237 output
['arc_hash_break']['hash_collisions'] = Kstat
[
238 "kstat.zfs.misc.arcstats.hash_collisions"
240 output
['arc_hash_break']['hash_elements'] = Kstat
[
241 "kstat.zfs.misc.arcstats.hash_elements"
243 output
['arc_hash_break']['hash_elements_max'] = Kstat
[
244 "kstat.zfs.misc.arcstats.hash_elements_max"
247 output
['arc_size_break'] = {}
248 if arc_size
> target_size
:
249 mfu_size
= (arc_size
- mru_size
)
250 output
['arc_size_break']['recently_used_cache_size'] = {
251 'per': fPerc(mru_size
, arc_size
),
252 'num': fBytes(mru_size
),
254 output
['arc_size_break']['frequently_used_cache_size'] = {
255 'per': fPerc(mfu_size
, arc_size
),
256 'num': fBytes(mfu_size
),
259 elif arc_size
< target_size
:
260 mfu_size
= (target_size
- mru_size
)
261 output
['arc_size_break']['recently_used_cache_size'] = {
262 'per': fPerc(mru_size
, target_size
),
263 'num': fBytes(mru_size
),
265 output
['arc_size_break']['frequently_used_cache_size'] = {
266 'per': fPerc(mfu_size
, target_size
),
267 'num': fBytes(mfu_size
),
270 ### ARC Hash Breakdown ###
271 hash_chain_max
= Kstat
["kstat.zfs.misc.arcstats.hash_chain_max"]
272 hash_chains
= Kstat
["kstat.zfs.misc.arcstats.hash_chains"]
273 hash_collisions
= Kstat
["kstat.zfs.misc.arcstats.hash_collisions"]
274 hash_elements
= Kstat
["kstat.zfs.misc.arcstats.hash_elements"]
275 hash_elements_max
= Kstat
["kstat.zfs.misc.arcstats.hash_elements_max"]
277 output
['arc_hash_break'] = {}
278 output
['arc_hash_break']['elements_max'] = fHits(hash_elements_max
)
279 output
['arc_hash_break']['elements_current'] = {
280 'per': fPerc(hash_elements
, hash_elements_max
),
281 'num': fHits(hash_elements
),
283 output
['arc_hash_break']['collisions'] = fHits(hash_collisions
)
284 output
['arc_hash_break']['chain_max'] = fHits(hash_chain_max
)
285 output
['arc_hash_break']['chains'] = fHits(hash_chains
)
290 def _arc_summary(Kstat
):
292 arc
= get_arc_summary(Kstat
)
294 sys
.stdout
.write("ARC Summary: (%s)\n" % arc
['health'])
296 sys
.stdout
.write("\tMemory Throttle Count:\t\t\t%s\n" %
297 arc
['memory_throttle_count'])
298 sys
.stdout
.write("\n")
301 sys
.stdout
.write("ARC Misc:\n")
302 sys
.stdout
.write("\tDeleted:\t\t\t\t%s\n" % arc
['arc_misc']['deleted'])
303 sys
.stdout
.write("\tMutex Misses:\t\t\t\t%s\n" %
304 arc
['arc_misc']['mutex_miss'])
305 sys
.stdout
.write("\tEvict Skips:\t\t\t\t%s\n" %
306 arc
['arc_misc']['mutex_miss'])
307 sys
.stdout
.write("\n")
310 sys
.stdout
.write("ARC Size:\t\t\t\t%s\t%s\n" % (
311 arc
['arc_sizing']['arc_size']['per'],
312 arc
['arc_sizing']['arc_size']['num']
315 sys
.stdout
.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % (
316 arc
['arc_sizing']['target_size']['per'],
317 arc
['arc_sizing']['target_size']['num'],
321 sys
.stdout
.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % (
322 arc
['arc_sizing']['target_min_size']['per'],
323 arc
['arc_sizing']['target_min_size']['num'],
327 sys
.stdout
.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % (
328 arc
['arc_sizing']['target_max_size']['ratio'],
329 arc
['arc_sizing']['target_max_size']['num'],
333 sys
.stdout
.write("\nARC Size Breakdown:\n")
334 sys
.stdout
.write("\tRecently Used Cache Size:\t%s\t%s\n" % (
335 arc
['arc_size_break']['recently_used_cache_size']['per'],
336 arc
['arc_size_break']['recently_used_cache_size']['num'],
339 sys
.stdout
.write("\tFrequently Used Cache Size:\t%s\t%s\n" % (
340 arc
['arc_size_break']['frequently_used_cache_size']['per'],
341 arc
['arc_size_break']['frequently_used_cache_size']['num'],
345 sys
.stdout
.write("\n")
347 ### ARC Hash Breakdown ###
348 sys
.stdout
.write("ARC Hash Breakdown:\n")
349 sys
.stdout
.write("\tElements Max:\t\t\t\t%s\n" %
350 arc
['arc_hash_break']['elements_max'])
351 sys
.stdout
.write("\tElements Current:\t\t%s\t%s\n" % (
352 arc
['arc_hash_break']['elements_current']['per'],
353 arc
['arc_hash_break']['elements_current']['num'],
356 sys
.stdout
.write("\tCollisions:\t\t\t\t%s\n" %
357 arc
['arc_hash_break']['collisions'])
358 sys
.stdout
.write("\tChain Max:\t\t\t\t%s\n" %
359 arc
['arc_hash_break']['chain_max'])
360 sys
.stdout
.write("\tChains:\t\t\t\t\t%s\n" %
361 arc
['arc_hash_break']['chains'])
364 def get_arc_efficiency(Kstat
):
367 arc_hits
= Kstat
["kstat.zfs.misc.arcstats.hits"]
368 arc_misses
= Kstat
["kstat.zfs.misc.arcstats.misses"]
369 demand_data_hits
= Kstat
["kstat.zfs.misc.arcstats.demand_data_hits"]
370 demand_data_misses
= Kstat
["kstat.zfs.misc.arcstats.demand_data_misses"]
371 demand_metadata_hits
= Kstat
[
372 "kstat.zfs.misc.arcstats.demand_metadata_hits"
374 demand_metadata_misses
= Kstat
[
375 "kstat.zfs.misc.arcstats.demand_metadata_misses"
377 mfu_ghost_hits
= Kstat
["kstat.zfs.misc.arcstats.mfu_ghost_hits"]
378 mfu_hits
= Kstat
["kstat.zfs.misc.arcstats.mfu_hits"]
379 mru_ghost_hits
= Kstat
["kstat.zfs.misc.arcstats.mru_ghost_hits"]
380 mru_hits
= Kstat
["kstat.zfs.misc.arcstats.mru_hits"]
381 prefetch_data_hits
= Kstat
["kstat.zfs.misc.arcstats.prefetch_data_hits"]
382 prefetch_data_misses
= Kstat
[
383 "kstat.zfs.misc.arcstats.prefetch_data_misses"
385 prefetch_metadata_hits
= Kstat
[
386 "kstat.zfs.misc.arcstats.prefetch_metadata_hits"
388 prefetch_metadata_misses
= Kstat
[
389 "kstat.zfs.misc.arcstats.prefetch_metadata_misses"
392 anon_hits
= arc_hits
- (
393 mfu_hits
+ mru_hits
+ mfu_ghost_hits
+ mru_ghost_hits
395 arc_accesses_total
= (arc_hits
+ arc_misses
)
396 demand_data_total
= (demand_data_hits
+ demand_data_misses
)
397 prefetch_data_total
= (prefetch_data_hits
+ prefetch_data_misses
)
398 real_hits
= (mfu_hits
+ mru_hits
)
400 output
["total_accesses"] = fHits(arc_accesses_total
)
401 output
["cache_hit_ratio"] = {
402 'per': fPerc(arc_hits
, arc_accesses_total
),
403 'num': fHits(arc_hits
),
405 output
["cache_miss_ratio"] = {
406 'per': fPerc(arc_misses
, arc_accesses_total
),
407 'num': fHits(arc_misses
),
409 output
["actual_hit_ratio"] = {
410 'per': fPerc(real_hits
, arc_accesses_total
),
411 'num': fHits(real_hits
),
413 output
["data_demand_efficiency"] = {
414 'per': fPerc(demand_data_hits
, demand_data_total
),
415 'num': fHits(demand_data_total
),
418 if prefetch_data_total
> 0:
419 output
["data_prefetch_efficiency"] = {
420 'per': fPerc(prefetch_data_hits
, prefetch_data_total
),
421 'num': fHits(prefetch_data_total
),
425 output
["cache_hits_by_cache_list"] = {}
426 output
["cache_hits_by_cache_list"]["anonymously_used"] = {
427 'per': fPerc(anon_hits
, arc_hits
),
428 'num': fHits(anon_hits
),
431 output
["most_recently_used"] = {
432 'per': fPerc(mru_hits
, arc_hits
),
433 'num': fHits(mru_hits
),
435 output
["most_frequently_used"] = {
436 'per': fPerc(mfu_hits
, arc_hits
),
437 'num': fHits(mfu_hits
),
439 output
["most_recently_used_ghost"] = {
440 'per': fPerc(mru_ghost_hits
, arc_hits
),
441 'num': fHits(mru_ghost_hits
),
443 output
["most_frequently_used_ghost"] = {
444 'per': fPerc(mfu_ghost_hits
, arc_hits
),
445 'num': fHits(mfu_ghost_hits
),
448 output
["cache_hits_by_data_type"] = {}
449 output
["cache_hits_by_data_type"]["demand_data"] = {
450 'per': fPerc(demand_data_hits
, arc_hits
),
451 'num': fHits(demand_data_hits
),
453 output
["cache_hits_by_data_type"]["prefetch_data"] = {
454 'per': fPerc(prefetch_data_hits
, arc_hits
),
455 'num': fHits(prefetch_data_hits
),
457 output
["cache_hits_by_data_type"]["demand_metadata"] = {
458 'per': fPerc(demand_metadata_hits
, arc_hits
),
459 'num': fHits(demand_metadata_hits
),
461 output
["cache_hits_by_data_type"]["prefetch_metadata"] = {
462 'per': fPerc(prefetch_metadata_hits
, arc_hits
),
463 'num': fHits(prefetch_metadata_hits
),
466 output
["cache_misses_by_data_type"] = {}
467 output
["cache_misses_by_data_type"]["demand_data"] = {
468 'per': fPerc(demand_data_misses
, arc_misses
),
469 'num': fHits(demand_data_misses
),
471 output
["cache_misses_by_data_type"]["prefetch_data"] = {
472 'per': fPerc(prefetch_data_misses
, arc_misses
),
473 'num': fHits(prefetch_data_misses
),
475 output
["cache_misses_by_data_type"]["demand_metadata"] = {
476 'per': fPerc(demand_metadata_misses
, arc_misses
),
477 'num': fHits(demand_metadata_misses
),
479 output
["cache_misses_by_data_type"]["prefetch_metadata"] = {
480 'per': fPerc(prefetch_metadata_misses
, arc_misses
),
481 'num': fHits(prefetch_metadata_misses
),
487 def _arc_efficiency(Kstat
):
488 arc
= get_arc_efficiency(Kstat
)
490 sys
.stdout
.write("ARC Total accesses:\t\t\t\t\t%s\n" %
491 arc
['total_accesses'])
492 sys
.stdout
.write("\tCache Hit Ratio:\t\t%s\t%s\n" % (
493 arc
['cache_hit_ratio']['per'],
494 arc
['cache_hit_ratio']['num'],
497 sys
.stdout
.write("\tCache Miss Ratio:\t\t%s\t%s\n" % (
498 arc
['cache_miss_ratio']['per'],
499 arc
['cache_miss_ratio']['num'],
503 sys
.stdout
.write("\tActual Hit Ratio:\t\t%s\t%s\n" % (
504 arc
['actual_hit_ratio']['per'],
505 arc
['actual_hit_ratio']['num'],
509 sys
.stdout
.write("\n")
510 sys
.stdout
.write("\tData Demand Efficiency:\t\t%s\t%s\n" % (
511 arc
['data_demand_efficiency']['per'],
512 arc
['data_demand_efficiency']['num'],
516 if 'data_prefetch_efficiency' in arc
:
517 sys
.stdout
.write("\tData Prefetch Efficiency:\t%s\t%s\n" % (
518 arc
['data_prefetch_efficiency']['per'],
519 arc
['data_prefetch_efficiency']['num'],
522 sys
.stdout
.write("\n")
524 sys
.stdout
.write("\tCACHE HITS BY CACHE LIST:\n")
525 if 'cache_hits_by_cache_list' in arc
:
526 sys
.stdout
.write("\t Anonymously Used:\t\t%s\t%s\n" % (
527 arc
['cache_hits_by_cache_list']['anonymously_used']['per'],
528 arc
['cache_hits_by_cache_list']['anonymously_used']['num'],
531 sys
.stdout
.write("\t Most Recently Used:\t\t%s\t%s\n" % (
532 arc
['most_recently_used']['per'],
533 arc
['most_recently_used']['num'],
536 sys
.stdout
.write("\t Most Frequently Used:\t\t%s\t%s\n" % (
537 arc
['most_frequently_used']['per'],
538 arc
['most_frequently_used']['num'],
541 sys
.stdout
.write("\t Most Recently Used Ghost:\t%s\t%s\n" % (
542 arc
['most_recently_used_ghost']['per'],
543 arc
['most_recently_used_ghost']['num'],
546 sys
.stdout
.write("\t Most Frequently Used Ghost:\t%s\t%s\n" % (
547 arc
['most_frequently_used_ghost']['per'],
548 arc
['most_frequently_used_ghost']['num'],
552 sys
.stdout
.write("\n\tCACHE HITS BY DATA TYPE:\n")
553 sys
.stdout
.write("\t Demand Data:\t\t\t%s\t%s\n" % (
554 arc
["cache_hits_by_data_type"]['demand_data']['per'],
555 arc
["cache_hits_by_data_type"]['demand_data']['num'],
558 sys
.stdout
.write("\t Prefetch Data:\t\t%s\t%s\n" % (
559 arc
["cache_hits_by_data_type"]['prefetch_data']['per'],
560 arc
["cache_hits_by_data_type"]['prefetch_data']['num'],
563 sys
.stdout
.write("\t Demand Metadata:\t\t%s\t%s\n" % (
564 arc
["cache_hits_by_data_type"]['demand_metadata']['per'],
565 arc
["cache_hits_by_data_type"]['demand_metadata']['num'],
568 sys
.stdout
.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
569 arc
["cache_hits_by_data_type"]['prefetch_metadata']['per'],
570 arc
["cache_hits_by_data_type"]['prefetch_metadata']['num'],
574 sys
.stdout
.write("\n\tCACHE MISSES BY DATA TYPE:\n")
575 sys
.stdout
.write("\t Demand Data:\t\t\t%s\t%s\n" % (
576 arc
["cache_misses_by_data_type"]['demand_data']['per'],
577 arc
["cache_misses_by_data_type"]['demand_data']['num'],
580 sys
.stdout
.write("\t Prefetch Data:\t\t%s\t%s\n" % (
581 arc
["cache_misses_by_data_type"]['prefetch_data']['per'],
582 arc
["cache_misses_by_data_type"]['prefetch_data']['num'],
585 sys
.stdout
.write("\t Demand Metadata:\t\t%s\t%s\n" % (
586 arc
["cache_misses_by_data_type"]['demand_metadata']['per'],
587 arc
["cache_misses_by_data_type"]['demand_metadata']['num'],
590 sys
.stdout
.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
591 arc
["cache_misses_by_data_type"]['prefetch_metadata']['per'],
592 arc
["cache_misses_by_data_type"]['prefetch_metadata']['num'],
597 def get_l2arc_summary(Kstat
):
600 l2_abort_lowmem
= Kstat
["kstat.zfs.misc.arcstats.l2_abort_lowmem"]
601 l2_cksum_bad
= Kstat
["kstat.zfs.misc.arcstats.l2_cksum_bad"]
602 l2_evict_lock_retry
= Kstat
["kstat.zfs.misc.arcstats.l2_evict_lock_retry"]
603 l2_evict_reading
= Kstat
["kstat.zfs.misc.arcstats.l2_evict_reading"]
604 l2_feeds
= Kstat
["kstat.zfs.misc.arcstats.l2_feeds"]
605 l2_free_on_write
= Kstat
["kstat.zfs.misc.arcstats.l2_free_on_write"]
606 l2_hdr_size
= Kstat
["kstat.zfs.misc.arcstats.l2_hdr_size"]
607 l2_hits
= Kstat
["kstat.zfs.misc.arcstats.l2_hits"]
608 l2_io_error
= Kstat
["kstat.zfs.misc.arcstats.l2_io_error"]
609 l2_misses
= Kstat
["kstat.zfs.misc.arcstats.l2_misses"]
610 l2_rw_clash
= Kstat
["kstat.zfs.misc.arcstats.l2_rw_clash"]
611 l2_size
= Kstat
["kstat.zfs.misc.arcstats.l2_size"]
612 l2_asize
= Kstat
["kstat.zfs.misc.arcstats.l2_asize"]
613 l2_writes_done
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_done"]
614 l2_writes_error
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_error"]
615 l2_writes_sent
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_sent"]
617 l2_access_total
= (l2_hits
+ l2_misses
)
618 output
['l2_health_count'] = (l2_writes_error
+ l2_cksum_bad
+ l2_io_error
)
620 output
['l2_access_total'] = l2_access_total
621 output
['l2_size'] = l2_size
622 output
['l2_asize'] = l2_asize
624 if l2_size
> 0 and l2_access_total
> 0:
626 if output
['l2_health_count'] > 0:
627 output
["health"] = "DEGRADED"
629 output
["health"] = "HEALTHY"
631 output
["low_memory_aborts"] = fHits(l2_abort_lowmem
)
632 output
["free_on_write"] = fHits(l2_free_on_write
)
633 output
["rw_clashes"] = fHits(l2_rw_clash
)
634 output
["bad_checksums"] = fHits(l2_cksum_bad
)
635 output
["io_errors"] = fHits(l2_io_error
)
637 output
["l2_arc_size"] = {}
638 output
["l2_arc_size"]["adative"] = fBytes(l2_size
)
639 output
["l2_arc_size"]["actual"] = {
640 'per': fPerc(l2_asize
, l2_size
),
641 'num': fBytes(l2_asize
)
643 output
["l2_arc_size"]["head_size"] = {
644 'per': fPerc(l2_hdr_size
, l2_size
),
645 'num': fBytes(l2_hdr_size
),
648 output
["l2_arc_evicts"] = {}
649 output
["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry
)
650 output
["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading
)
652 output
['l2_arc_breakdown'] = {}
653 output
['l2_arc_breakdown']['value'] = fHits(l2_access_total
)
654 output
['l2_arc_breakdown']['hit_ratio'] = {
655 'per': fPerc(l2_hits
, l2_access_total
),
656 'num': fHits(l2_hits
),
658 output
['l2_arc_breakdown']['miss_ratio'] = {
659 'per': fPerc(l2_misses
, l2_access_total
),
660 'num': fHits(l2_misses
),
662 output
['l2_arc_breakdown']['feeds'] = fHits(l2_feeds
)
664 output
['l2_arc_buffer'] = {}
666 output
['l2_arc_writes'] = {}
667 output
['l2_writes_done'] = l2_writes_done
668 output
['l2_writes_sent'] = l2_writes_sent
669 if l2_writes_done
!= l2_writes_sent
:
670 output
['l2_arc_writes']['writes_sent'] = {
672 'num': fHits(l2_writes_sent
),
674 output
['l2_arc_writes']['done_ratio'] = {
675 'per': fPerc(l2_writes_done
, l2_writes_sent
),
676 'num': fHits(l2_writes_done
),
678 output
['l2_arc_writes']['error_ratio'] = {
679 'per': fPerc(l2_writes_error
, l2_writes_sent
),
680 'num': fHits(l2_writes_error
),
683 output
['l2_arc_writes']['writes_sent'] = {
685 'num': fHits(l2_writes_sent
),
691 def _l2arc_summary(Kstat
):
693 arc
= get_l2arc_summary(Kstat
)
695 if arc
['l2_size'] > 0 and arc
['l2_access_total'] > 0:
696 sys
.stdout
.write("L2 ARC Summary: ")
697 if arc
['l2_health_count'] > 0:
698 sys
.stdout
.write("(DEGRADED)\n")
700 sys
.stdout
.write("(HEALTHY)\n")
701 sys
.stdout
.write("\tLow Memory Aborts:\t\t\t%s\n" %
702 arc
['low_memory_aborts'])
703 sys
.stdout
.write("\tFree on Write:\t\t\t\t%s\n" % arc
['free_on_write'])
704 sys
.stdout
.write("\tR/W Clashes:\t\t\t\t%s\n" % arc
['rw_clashes'])
705 sys
.stdout
.write("\tBad Checksums:\t\t\t\t%s\n" % arc
['bad_checksums'])
706 sys
.stdout
.write("\tIO Errors:\t\t\t\t%s\n" % arc
['io_errors'])
707 sys
.stdout
.write("\n")
709 sys
.stdout
.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
710 arc
["l2_arc_size"]["adative"])
711 sys
.stdout
.write("\tCompressed:\t\t\t%s\t%s\n" % (
712 arc
["l2_arc_size"]["actual"]["per"],
713 arc
["l2_arc_size"]["actual"]["num"],
716 sys
.stdout
.write("\tHeader Size:\t\t\t%s\t%s\n" % (
717 arc
["l2_arc_size"]["head_size"]["per"],
718 arc
["l2_arc_size"]["head_size"]["num"],
721 sys
.stdout
.write("\n")
723 if arc
["l2_arc_evicts"]['lock_retries'] + \
724 arc
["l2_arc_evicts"]["reading"] > 0:
725 sys
.stdout
.write("L2 ARC Evicts:\n")
726 sys
.stdout
.write("\tLock Retries:\t\t\t\t%s\n" %
727 arc
["l2_arc_evicts"]['lock_retries'])
728 sys
.stdout
.write("\tUpon Reading:\t\t\t\t%s\n" %
729 arc
["l2_arc_evicts"]["reading"])
730 sys
.stdout
.write("\n")
732 sys
.stdout
.write("L2 ARC Breakdown:\t\t\t\t%s\n" %
733 arc
['l2_arc_breakdown']['value'])
734 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
735 arc
['l2_arc_breakdown']['hit_ratio']['per'],
736 arc
['l2_arc_breakdown']['hit_ratio']['num'],
740 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
741 arc
['l2_arc_breakdown']['miss_ratio']['per'],
742 arc
['l2_arc_breakdown']['miss_ratio']['num'],
746 sys
.stdout
.write("\tFeeds:\t\t\t\t\t%s\n" %
747 arc
['l2_arc_breakdown']['feeds'])
748 sys
.stdout
.write("\n")
750 sys
.stdout
.write("L2 ARC Writes:\n")
751 if arc
['l2_writes_done'] != arc
['l2_writes_sent']:
752 sys
.stdout
.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % (
753 arc
['l2_arc_writes']['writes_sent']['value'],
754 arc
['l2_arc_writes']['writes_sent']['num'],
757 sys
.stdout
.write("\t Done Ratio:\t\t\t%s\t%s\n" % (
758 arc
['l2_arc_writes']['done_ratio']['per'],
759 arc
['l2_arc_writes']['done_ratio']['num'],
762 sys
.stdout
.write("\t Error Ratio:\t\t\t%s\t%s\n" % (
763 arc
['l2_arc_writes']['error_ratio']['per'],
764 arc
['l2_arc_writes']['error_ratio']['num'],
768 sys
.stdout
.write("\tWrites Sent:\t\t\t%s\t%s\n" % (
769 arc
['l2_arc_writes']['writes_sent']['per'],
770 arc
['l2_arc_writes']['writes_sent']['num'],
775 def get_dmu_summary(Kstat
):
778 zfetch_bogus_streams
= Kstat
["kstat.zfs.misc.zfetchstats.bogus_streams"]
779 zfetch_colinear_hits
= Kstat
["kstat.zfs.misc.zfetchstats.colinear_hits"]
780 zfetch_colinear_misses
= \
781 Kstat
["kstat.zfs.misc.zfetchstats.colinear_misses"]
782 zfetch_hits
= Kstat
["kstat.zfs.misc.zfetchstats.hits"]
783 zfetch_misses
= Kstat
["kstat.zfs.misc.zfetchstats.misses"]
784 zfetch_reclaim_failures
= \
785 Kstat
["kstat.zfs.misc.zfetchstats.reclaim_failures"]
786 zfetch_reclaim_successes
= \
787 Kstat
["kstat.zfs.misc.zfetchstats.reclaim_successes"]
788 zfetch_streams_noresets
= \
789 Kstat
["kstat.zfs.misc.zfetchstats.streams_noresets"]
790 zfetch_streams_resets
= Kstat
["kstat.zfs.misc.zfetchstats.streams_resets"]
791 zfetch_stride_hits
= Kstat
["kstat.zfs.misc.zfetchstats.stride_hits"]
792 zfetch_stride_misses
= Kstat
["kstat.zfs.misc.zfetchstats.stride_misses"]
794 zfetch_access_total
= (zfetch_hits
+ zfetch_misses
)
795 zfetch_colinear_total
= (zfetch_colinear_hits
+ zfetch_colinear_misses
)
796 zfetch_health_count
= (zfetch_bogus_streams
)
797 zfetch_reclaim_total
= (zfetch_reclaim_successes
+ zfetch_reclaim_failures
)
798 zfetch_streams_total
= (zfetch_streams_resets
+ zfetch_streams_noresets
+
799 zfetch_bogus_streams
)
800 zfetch_stride_total
= (zfetch_stride_hits
+ zfetch_stride_misses
)
801 output
['zfetch_access_total'] = zfetch_access_total
803 if zfetch_access_total
> 0:
805 output
['file_level_prefetch'] = {}
806 if zfetch_health_count
> 0:
807 output
['file_level_prefetch']['health'] = 'DEGRADED'
809 output
['file_level_prefetch']['health'] = 'HEALTHY'
812 output
['dmu']['efficiency'] = {}
813 output
['dmu']['efficiency']['value'] = fHits(zfetch_access_total
)
814 output
['dmu']['efficiency']['hit_ratio'] = {
815 'per': fPerc(zfetch_hits
, zfetch_access_total
),
816 'num': fHits(zfetch_hits
),
818 output
['dmu']['efficiency']['miss_ratio'] = {
819 'per': fPerc(zfetch_misses
, zfetch_access_total
),
820 'num': fHits(zfetch_misses
),
823 output
['dmu']['colinear'] = {}
824 output
['dmu']['colinear']['value'] = fHits(zfetch_colinear_total
)
825 output
['dmu']['colinear']['hit_ratio'] = {
826 'per': fPerc(zfetch_colinear_hits
, zfetch_colinear_total
),
827 'num': fHits(zfetch_colinear_hits
),
829 output
['dmu']['colinear']['miss_ratio'] = {
830 'per': fPerc(zfetch_colinear_misses
, zfetch_colinear_total
),
831 'num': fHits(zfetch_colinear_misses
),
834 output
['dmu']['stride'] = {}
835 output
['dmu']['stride']['value'] = fHits(zfetch_stride_total
)
836 output
['dmu']['stride']['hit_ratio'] = {
837 'per': fPerc(zfetch_stride_hits
, zfetch_stride_total
),
838 'num': fHits(zfetch_stride_hits
),
840 output
['dmu']['stride']['miss_ratio'] = {
841 'per': fPerc(zfetch_stride_misses
, zfetch_stride_total
),
842 'num': fHits(zfetch_stride_misses
),
845 output
['dmu_misc'] = {}
846 if zfetch_health_count
> 0:
847 output
['dmu_misc']['status'] = "FAULTED"
849 output
['dmu_misc']['status'] = ""
851 output
['dmu_misc']['reclaim'] = {}
852 output
['dmu_misc']['reclaim']['value'] = fHits(zfetch_reclaim_total
)
853 output
['dmu_misc']['reclaim']['successes'] = {
854 'per': fPerc(zfetch_reclaim_successes
, zfetch_reclaim_total
),
855 'num': fHits(zfetch_reclaim_successes
),
857 output
['dmu_misc']['reclaim']['failure'] = {
858 'per': fPerc(zfetch_reclaim_failures
, zfetch_reclaim_total
),
859 'num': fHits(zfetch_reclaim_failures
),
862 output
['dmu_misc']['streams'] = {}
863 output
['dmu_misc']['streams']['value'] = fHits(zfetch_streams_total
)
864 output
['dmu_misc']['streams']['plus_resets'] = {
865 'per': fPerc(zfetch_streams_resets
, zfetch_streams_total
),
866 'num': fHits(zfetch_streams_resets
),
868 output
['dmu_misc']['streams']['neg_resets'] = {
869 'per': fPerc(zfetch_streams_noresets
, zfetch_streams_total
),
870 'num': fHits(zfetch_streams_noresets
),
872 output
['dmu_misc']['streams']['bogus'] = fHits(zfetch_bogus_streams
)
877 def _dmu_summary(Kstat
):
879 arc
= get_dmu_summary(Kstat
)
881 if arc
['zfetch_access_total'] > 0:
882 sys
.stdout
.write("File-Level Prefetch: (%s)" %
883 arc
['file_level_prefetch']['health'])
884 sys
.stdout
.write("\n")
886 sys
.stdout
.write("DMU Efficiency:\t\t\t\t\t%s\n" %
887 arc
['dmu']['efficiency']['value'])
888 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
889 arc
['dmu']['efficiency']['hit_ratio']['per'],
890 arc
['dmu']['efficiency']['hit_ratio']['num'],
893 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
894 arc
['dmu']['efficiency']['miss_ratio']['per'],
895 arc
['dmu']['efficiency']['miss_ratio']['num'],
899 sys
.stdout
.write("\n")
901 sys
.stdout
.write("\tColinear:\t\t\t\t%s\n" %
902 arc
['dmu']['colinear']['value'])
903 sys
.stdout
.write("\t Hit Ratio:\t\t\t%s\t%s\n" % (
904 arc
['dmu']['colinear']['hit_ratio']['per'],
905 arc
['dmu']['colinear']['hit_ratio']['num'],
909 sys
.stdout
.write("\t Miss Ratio:\t\t\t%s\t%s\n" % (
910 arc
['dmu']['colinear']['miss_ratio']['per'],
911 arc
['dmu']['colinear']['miss_ratio']['num'],
915 sys
.stdout
.write("\n")
917 sys
.stdout
.write("\tStride:\t\t\t\t\t%s\n" %
918 arc
['dmu']['stride']['value'])
919 sys
.stdout
.write("\t Hit Ratio:\t\t\t%s\t%s\n" % (
920 arc
['dmu']['stride']['hit_ratio']['per'],
921 arc
['dmu']['stride']['hit_ratio']['num'],
925 sys
.stdout
.write("\t Miss Ratio:\t\t\t%s\t%s\n" % (
926 arc
['dmu']['stride']['miss_ratio']['per'],
927 arc
['dmu']['stride']['miss_ratio']['num'],
931 sys
.stdout
.write("\n")
932 sys
.stdout
.write("DMU Misc: %s\n" % arc
['dmu_misc']['status'])
934 sys
.stdout
.write("\tReclaim:\t\t\t\t%s\n" %
935 arc
['dmu_misc']['reclaim']['value'])
936 sys
.stdout
.write("\t Successes:\t\t\t%s\t%s\n" % (
937 arc
['dmu_misc']['reclaim']['successes']['per'],
938 arc
['dmu_misc']['reclaim']['successes']['num'],
942 sys
.stdout
.write("\t Failures:\t\t\t%s\t%s\n" % (
943 arc
['dmu_misc']['reclaim']['failure']['per'],
944 arc
['dmu_misc']['reclaim']['failure']['num'],
948 sys
.stdout
.write("\n\tStreams:\t\t\t\t%s\n" %
949 arc
['dmu_misc']['streams']['value'])
950 sys
.stdout
.write("\t +Resets:\t\t\t%s\t%s\n" % (
951 arc
['dmu_misc']['streams']['plus_resets']['per'],
952 arc
['dmu_misc']['streams']['plus_resets']['num'],
956 sys
.stdout
.write("\t -Resets:\t\t\t%s\t%s\n" % (
957 arc
['dmu_misc']['streams']['neg_resets']['per'],
958 arc
['dmu_misc']['streams']['neg_resets']['num'],
962 sys
.stdout
.write("\t Bogus:\t\t\t\t%s\n" %
963 arc
['dmu_misc']['streams']['bogus'])
966 def get_vdev_summary(Kstat
):
969 vdev_cache_delegations
= \
970 Kstat
["kstat.zfs.misc.vdev_cache_stats.delegations"]
971 vdev_cache_misses
= Kstat
["kstat.zfs.misc.vdev_cache_stats.misses"]
972 vdev_cache_hits
= Kstat
["kstat.zfs.misc.vdev_cache_stats.hits"]
973 vdev_cache_total
= (vdev_cache_misses
+ vdev_cache_hits
+
974 vdev_cache_delegations
)
976 output
['vdev_cache_total'] = vdev_cache_total
978 if vdev_cache_total
> 0:
979 output
['summary'] = fHits(vdev_cache_total
)
980 output
['hit_ratio'] = {
981 'per': fPerc(vdev_cache_hits
, vdev_cache_total
),
982 'num': fHits(vdev_cache_hits
),
984 output
['miss_ratio'] = {
985 'per': fPerc(vdev_cache_misses
, vdev_cache_total
),
986 'num': fHits(vdev_cache_misses
),
988 output
['delegations'] = {
989 'per': fPerc(vdev_cache_delegations
, vdev_cache_total
),
990 'num': fHits(vdev_cache_delegations
),
996 def _vdev_summary(Kstat
):
997 arc
= get_vdev_summary(Kstat
)
999 if arc
['vdev_cache_total'] > 0:
1000 sys
.stdout
.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc
['summary'])
1001 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
1002 arc
['hit_ratio']['per'],
1003 arc
['hit_ratio']['num'],
1005 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
1006 arc
['miss_ratio']['per'],
1007 arc
['miss_ratio']['num'],
1009 sys
.stdout
.write("\tDelegations:\t\t\t%s\t%s\n" % (
1010 arc
['delegations']['per'],
1011 arc
['delegations']['num'],
1015 def _tunable_summary(Kstat
):
1016 global show_tunable_descriptions
1017 global alternate_tunable_layout
1019 names
= listdir("/sys/module/zfs/parameters/")
1023 with
open("/sys/module/zfs/parameters/" + name
) as f
: value
= f
.read()
1024 values
[name
] = value
.strip()
1028 if show_tunable_descriptions
:
1030 command
= ["/sbin/modinfo", "zfs", "-0"]
1031 p
= Popen(command
, stdin
=PIPE
, stdout
=PIPE
,
1032 stderr
=PIPE
, shell
=False, close_fds
=True)
1035 description_list
= p
.communicate()[0].strip().split('\0')
1037 if p
.returncode
== 0:
1038 for tunable
in description_list
:
1039 if tunable
[0:5] == 'parm:':
1040 tunable
= tunable
[5:].strip()
1041 name
, description
= tunable
.split(':', 1)
1043 description
= "Description unavailable"
1044 descriptions
[name
] = description
1046 sys
.stderr
.write("%s: '%s' exited with code %i\n" %
1047 (sys
.argv
[0], command
[0], p
.returncode
))
1048 sys
.stderr
.write("Tunable descriptions will be disabled.\n")
1049 except OSError as e
:
1050 sys
.stderr
.write("%s: Cannot run '%s': %s\n" %
1051 (sys
.argv
[0], command
[0], e
.strerror
))
1052 sys
.stderr
.write("Tunable descriptions will be disabled.\n")
1054 sys
.stdout
.write("ZFS Tunable:\n")
1059 format
= "\t%-50s%s\n"
1060 if alternate_tunable_layout
:
1061 format
= "\t%s=%s\n"
1063 if show_tunable_descriptions
and name
in descriptions
:
1064 sys
.stdout
.write("\t# %s\n" % descriptions
[name
])
1066 sys
.stdout
.write(format
% (name
, values
[name
]))
1080 daydate
= time
.strftime("%a %b %d %H:%M:%S %Y")
1083 sys
.stdout
.write("ZFS Subsystem Report\t\t\t\t%s" % daydate
)
1088 sys
.stdout
.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n")
1089 sys
.stdout
.write("\t -h, --help : "
1090 "Print this help message and exit\n")
1091 sys
.stdout
.write("\t -a, --alternate : "
1092 "Show an alternate sysctl layout\n")
1093 sys
.stdout
.write("\t -d, --description : "
1094 "Show the sysctl descriptions\n")
1095 sys
.stdout
.write("\t -p PAGE, --page=PAGE : "
1096 "Select a single output page to display,\n")
1097 sys
.stdout
.write("\t "
1098 "should be an integer between 1 and " + str(len(unSub
)) + "\n\n")
1099 sys
.stdout
.write("Examples:\n")
1100 sys
.stdout
.write("\tarc_summary.py -a\n")
1101 sys
.stdout
.write("\tarc_summary.py -p 4\n")
1102 sys
.stdout
.write("\tarc_summary.py -ad\n")
1103 sys
.stdout
.write("\tarc_summary.py --page=2\n")
1106 global show_tunable_descriptions
1107 global alternate_tunable_layout
1109 opts
, args
= getopt
.getopt(
1110 sys
.argv
[1:], "adp:h", ["alternate", "description", "page=", "help"]
1114 for opt
, arg
in opts
:
1115 if opt
in ('-a', '--alternate'):
1117 if opt
in ('-d', '--description'):
1119 if opt
in ('-p', '--page'):
1121 if opt
in ('-h', '--help'):
1127 alternate_tunable_layout
= 'a' in args
1128 show_tunable_descriptions
= 'd' in args
1134 pages
.append(unSub
[int(args
['p']) - 1])
1135 except IndexError as e
:
1136 sys
.stderr
.write('the argument to -p must be between 1 and ' +
1137 str(len(unSub
)) + '\n')
1147 if __name__
== '__main__':