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
)
70 load_proc_kstats('/proc/spl/kstat/zfs/arcstats',
71 'kstat.zfs.misc.arcstats.')
72 load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats',
73 'kstat.zfs.misc.zfetchstats.')
74 load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats',
75 'kstat.zfs.misc.vdev_cache_stats.')
81 sys
.stdout
.write("\n")
83 sys
.stdout
.write("%s" % "----")
84 sys
.stdout
.write("\n")
88 sys
.stdout
.write("\n")
91 def fBytes(Bytes
=0, Decimal
=2):
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"
118 return str("%d" % 0) + "\tBytes"
120 return str("%d" % Bytes
) + "\tBytes"
123 def fHits(Hits
=0, Decimal
=2):
134 return str("%0." + str(Decimal
) + "f") % (Hits
/ Shits
) + "S"
136 return str("%0." + str(Decimal
) + "f") % (Hits
/ shits
) + "s"
138 return str("%0." + str(Decimal
) + "f") % (Hits
/ Qhits
) + "Q"
140 return str("%0." + str(Decimal
) + "f") % (Hits
/ qhits
) + "q"
142 return str("%0." + str(Decimal
) + "f") % (Hits
/ thits
) + "t"
144 return str("%0." + str(Decimal
) + "f") % (Hits
/ bhits
) + "b"
146 return str("%0." + str(Decimal
) + "f") % (Hits
/ mhits
) + "m"
148 return str("%0." + str(Decimal
) + "f") % (Hits
/ khits
) + "k"
152 return str("%d" % Hits
)
155 def fPerc(lVal
=0, rVal
=0, Decimal
=2):
157 return str("%0." + str(Decimal
) + "f") % (100 * (lVal
/ rVal
)) + "%"
159 return str("%0." + str(Decimal
) + "f") % 100 + "%"
162 def get_arc_summary(Kstat
):
165 memory_throttle_count
= Kstat
[
166 "kstat.zfs.misc.arcstats.memory_throttle_count"
169 if memory_throttle_count
> 0:
170 output
['health'] = 'THROTTLED'
172 output
['health'] = 'HEALTHY'
174 output
['memory_throttle_count'] = fHits(memory_throttle_count
)
177 deleted
= Kstat
["kstat.zfs.misc.arcstats.deleted"]
178 mutex_miss
= Kstat
["kstat.zfs.misc.arcstats.mutex_miss"]
181 output
["arc_misc"] = {}
182 output
["arc_misc"]["deleted"] = fHits(deleted
)
183 output
["arc_misc"]['mutex_miss'] = fHits(mutex_miss
)
184 output
["arc_misc"]['evict_skips'] = fHits(mutex_miss
)
187 arc_size
= Kstat
["kstat.zfs.misc.arcstats.size"]
188 mru_size
= Kstat
["kstat.zfs.misc.arcstats.p"]
189 target_max_size
= Kstat
["kstat.zfs.misc.arcstats.c_max"]
190 target_min_size
= Kstat
["kstat.zfs.misc.arcstats.c_min"]
191 target_size
= Kstat
["kstat.zfs.misc.arcstats.c"]
193 target_size_ratio
= (target_max_size
/ target_min_size
)
196 output
['arc_sizing'] = {}
197 output
['arc_sizing']['arc_size'] = {
198 'per': fPerc(arc_size
, target_max_size
),
199 'num': fBytes(arc_size
),
201 output
['arc_sizing']['target_max_size'] = {
202 'ratio': target_size_ratio
,
203 'num': fBytes(target_max_size
),
205 output
['arc_sizing']['target_min_size'] = {
206 'per': fPerc(target_min_size
, target_max_size
),
207 'num': fBytes(target_min_size
),
209 output
['arc_sizing']['target_size'] = {
210 'per': fPerc(target_size
, target_max_size
),
211 'num': fBytes(target_size
),
215 output
['arc_hash_break'] = {}
216 output
['arc_hash_break']['hash_chain_max'] = Kstat
[
217 "kstat.zfs.misc.arcstats.hash_chain_max"
219 output
['arc_hash_break']['hash_chains'] = Kstat
[
220 "kstat.zfs.misc.arcstats.hash_chains"
222 output
['arc_hash_break']['hash_collisions'] = Kstat
[
223 "kstat.zfs.misc.arcstats.hash_collisions"
225 output
['arc_hash_break']['hash_elements'] = Kstat
[
226 "kstat.zfs.misc.arcstats.hash_elements"
228 output
['arc_hash_break']['hash_elements_max'] = Kstat
[
229 "kstat.zfs.misc.arcstats.hash_elements_max"
232 output
['arc_size_break'] = {}
233 if arc_size
> target_size
:
234 mfu_size
= (arc_size
- mru_size
)
235 output
['arc_size_break']['recently_used_cache_size'] = {
236 'per': fPerc(mru_size
, arc_size
),
237 'num': fBytes(mru_size
),
239 output
['arc_size_break']['frequently_used_cache_size'] = {
240 'per': fPerc(mfu_size
, arc_size
),
241 'num': fBytes(mfu_size
),
244 elif arc_size
< target_size
:
245 mfu_size
= (target_size
- mru_size
)
246 output
['arc_size_break']['recently_used_cache_size'] = {
247 'per': fPerc(mru_size
, target_size
),
248 'num': fBytes(mru_size
),
250 output
['arc_size_break']['frequently_used_cache_size'] = {
251 'per': fPerc(mfu_size
, target_size
),
252 'num': fBytes(mfu_size
),
256 hash_chain_max
= Kstat
["kstat.zfs.misc.arcstats.hash_chain_max"]
257 hash_chains
= Kstat
["kstat.zfs.misc.arcstats.hash_chains"]
258 hash_collisions
= Kstat
["kstat.zfs.misc.arcstats.hash_collisions"]
259 hash_elements
= Kstat
["kstat.zfs.misc.arcstats.hash_elements"]
260 hash_elements_max
= Kstat
["kstat.zfs.misc.arcstats.hash_elements_max"]
262 output
['arc_hash_break'] = {}
263 output
['arc_hash_break']['elements_max'] = fHits(hash_elements_max
)
264 output
['arc_hash_break']['elements_current'] = {
265 'per': fPerc(hash_elements
, hash_elements_max
),
266 'num': fHits(hash_elements
),
268 output
['arc_hash_break']['collisions'] = fHits(hash_collisions
)
269 output
['arc_hash_break']['chain_max'] = fHits(hash_chain_max
)
270 output
['arc_hash_break']['chains'] = fHits(hash_chains
)
275 def _arc_summary(Kstat
):
277 arc
= get_arc_summary(Kstat
)
279 sys
.stdout
.write("ARC Summary: (%s)\n" % arc
['health'])
281 sys
.stdout
.write("\tMemory Throttle Count:\t\t\t%s\n" %
282 arc
['memory_throttle_count'])
283 sys
.stdout
.write("\n")
286 sys
.stdout
.write("ARC Misc:\n")
287 sys
.stdout
.write("\tDeleted:\t\t\t\t%s\n" % arc
['arc_misc']['deleted'])
288 sys
.stdout
.write("\tMutex Misses:\t\t\t\t%s\n" %
289 arc
['arc_misc']['mutex_miss'])
290 sys
.stdout
.write("\tEvict Skips:\t\t\t\t%s\n" %
291 arc
['arc_misc']['mutex_miss'])
292 sys
.stdout
.write("\n")
295 sys
.stdout
.write("ARC Size:\t\t\t\t%s\t%s\n" % (
296 arc
['arc_sizing']['arc_size']['per'],
297 arc
['arc_sizing']['arc_size']['num']
300 sys
.stdout
.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % (
301 arc
['arc_sizing']['target_size']['per'],
302 arc
['arc_sizing']['target_size']['num'],
306 sys
.stdout
.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % (
307 arc
['arc_sizing']['target_min_size']['per'],
308 arc
['arc_sizing']['target_min_size']['num'],
312 sys
.stdout
.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % (
313 arc
['arc_sizing']['target_max_size']['ratio'],
314 arc
['arc_sizing']['target_max_size']['num'],
318 sys
.stdout
.write("\nARC Size Breakdown:\n")
319 sys
.stdout
.write("\tRecently Used Cache Size:\t%s\t%s\n" % (
320 arc
['arc_size_break']['recently_used_cache_size']['per'],
321 arc
['arc_size_break']['recently_used_cache_size']['num'],
324 sys
.stdout
.write("\tFrequently Used Cache Size:\t%s\t%s\n" % (
325 arc
['arc_size_break']['frequently_used_cache_size']['per'],
326 arc
['arc_size_break']['frequently_used_cache_size']['num'],
330 sys
.stdout
.write("\n")
333 sys
.stdout
.write("ARC Hash Breakdown:\n")
334 sys
.stdout
.write("\tElements Max:\t\t\t\t%s\n" %
335 arc
['arc_hash_break']['elements_max'])
336 sys
.stdout
.write("\tElements Current:\t\t%s\t%s\n" % (
337 arc
['arc_hash_break']['elements_current']['per'],
338 arc
['arc_hash_break']['elements_current']['num'],
341 sys
.stdout
.write("\tCollisions:\t\t\t\t%s\n" %
342 arc
['arc_hash_break']['collisions'])
343 sys
.stdout
.write("\tChain Max:\t\t\t\t%s\n" %
344 arc
['arc_hash_break']['chain_max'])
345 sys
.stdout
.write("\tChains:\t\t\t\t\t%s\n" %
346 arc
['arc_hash_break']['chains'])
349 def get_arc_efficiency(Kstat
):
352 arc_hits
= Kstat
["kstat.zfs.misc.arcstats.hits"]
353 arc_misses
= Kstat
["kstat.zfs.misc.arcstats.misses"]
354 demand_data_hits
= Kstat
["kstat.zfs.misc.arcstats.demand_data_hits"]
355 demand_data_misses
= Kstat
["kstat.zfs.misc.arcstats.demand_data_misses"]
356 demand_metadata_hits
= Kstat
[
357 "kstat.zfs.misc.arcstats.demand_metadata_hits"
359 demand_metadata_misses
= Kstat
[
360 "kstat.zfs.misc.arcstats.demand_metadata_misses"
362 mfu_ghost_hits
= Kstat
["kstat.zfs.misc.arcstats.mfu_ghost_hits"]
363 mfu_hits
= Kstat
["kstat.zfs.misc.arcstats.mfu_hits"]
364 mru_ghost_hits
= Kstat
["kstat.zfs.misc.arcstats.mru_ghost_hits"]
365 mru_hits
= Kstat
["kstat.zfs.misc.arcstats.mru_hits"]
366 prefetch_data_hits
= Kstat
["kstat.zfs.misc.arcstats.prefetch_data_hits"]
367 prefetch_data_misses
= Kstat
[
368 "kstat.zfs.misc.arcstats.prefetch_data_misses"
370 prefetch_metadata_hits
= Kstat
[
371 "kstat.zfs.misc.arcstats.prefetch_metadata_hits"
373 prefetch_metadata_misses
= Kstat
[
374 "kstat.zfs.misc.arcstats.prefetch_metadata_misses"
377 anon_hits
= arc_hits
- (
378 mfu_hits
+ mru_hits
+ mfu_ghost_hits
+ mru_ghost_hits
380 arc_accesses_total
= (arc_hits
+ arc_misses
)
381 demand_data_total
= (demand_data_hits
+ demand_data_misses
)
382 prefetch_data_total
= (prefetch_data_hits
+ prefetch_data_misses
)
383 real_hits
= (mfu_hits
+ mru_hits
)
385 output
["total_accesses"] = fHits(arc_accesses_total
)
386 output
["cache_hit_ratio"] = {
387 'per': fPerc(arc_hits
, arc_accesses_total
),
388 'num': fHits(arc_hits
),
390 output
["cache_miss_ratio"] = {
391 'per': fPerc(arc_misses
, arc_accesses_total
),
392 'num': fHits(arc_misses
),
394 output
["actual_hit_ratio"] = {
395 'per': fPerc(real_hits
, arc_accesses_total
),
396 'num': fHits(real_hits
),
398 output
["data_demand_efficiency"] = {
399 'per': fPerc(demand_data_hits
, demand_data_total
),
400 'num': fHits(demand_data_total
),
403 if prefetch_data_total
> 0:
404 output
["data_prefetch_efficiency"] = {
405 'per': fPerc(prefetch_data_hits
, prefetch_data_total
),
406 'num': fHits(prefetch_data_total
),
410 output
["cache_hits_by_cache_list"] = {}
411 output
["cache_hits_by_cache_list"]["anonymously_used"] = {
412 'per': fPerc(anon_hits
, arc_hits
),
413 'num': fHits(anon_hits
),
416 output
["most_recently_used"] = {
417 'per': fPerc(mru_hits
, arc_hits
),
418 'num': fHits(mru_hits
),
420 output
["most_frequently_used"] = {
421 'per': fPerc(mfu_hits
, arc_hits
),
422 'num': fHits(mfu_hits
),
424 output
["most_recently_used_ghost"] = {
425 'per': fPerc(mru_ghost_hits
, arc_hits
),
426 'num': fHits(mru_ghost_hits
),
428 output
["most_frequently_used_ghost"] = {
429 'per': fPerc(mfu_ghost_hits
, arc_hits
),
430 'num': fHits(mfu_ghost_hits
),
433 output
["cache_hits_by_data_type"] = {}
434 output
["cache_hits_by_data_type"]["demand_data"] = {
435 'per': fPerc(demand_data_hits
, arc_hits
),
436 'num': fHits(demand_data_hits
),
438 output
["cache_hits_by_data_type"]["prefetch_data"] = {
439 'per': fPerc(prefetch_data_hits
, arc_hits
),
440 'num': fHits(prefetch_data_hits
),
442 output
["cache_hits_by_data_type"]["demand_metadata"] = {
443 'per': fPerc(demand_metadata_hits
, arc_hits
),
444 'num': fHits(demand_metadata_hits
),
446 output
["cache_hits_by_data_type"]["prefetch_metadata"] = {
447 'per': fPerc(prefetch_metadata_hits
, arc_hits
),
448 'num': fHits(prefetch_metadata_hits
),
451 output
["cache_misses_by_data_type"] = {}
452 output
["cache_misses_by_data_type"]["demand_data"] = {
453 'per': fPerc(demand_data_misses
, arc_misses
),
454 'num': fHits(demand_data_misses
),
456 output
["cache_misses_by_data_type"]["prefetch_data"] = {
457 'per': fPerc(prefetch_data_misses
, arc_misses
),
458 'num': fHits(prefetch_data_misses
),
460 output
["cache_misses_by_data_type"]["demand_metadata"] = {
461 'per': fPerc(demand_metadata_misses
, arc_misses
),
462 'num': fHits(demand_metadata_misses
),
464 output
["cache_misses_by_data_type"]["prefetch_metadata"] = {
465 'per': fPerc(prefetch_metadata_misses
, arc_misses
),
466 'num': fHits(prefetch_metadata_misses
),
472 def _arc_efficiency(Kstat
):
473 arc
= get_arc_efficiency(Kstat
)
475 sys
.stdout
.write("ARC Total accesses:\t\t\t\t\t%s\n" %
476 arc
['total_accesses'])
477 sys
.stdout
.write("\tCache Hit Ratio:\t\t%s\t%s\n" % (
478 arc
['cache_hit_ratio']['per'],
479 arc
['cache_hit_ratio']['num'],
482 sys
.stdout
.write("\tCache Miss Ratio:\t\t%s\t%s\n" % (
483 arc
['cache_miss_ratio']['per'],
484 arc
['cache_miss_ratio']['num'],
488 sys
.stdout
.write("\tActual Hit Ratio:\t\t%s\t%s\n" % (
489 arc
['actual_hit_ratio']['per'],
490 arc
['actual_hit_ratio']['num'],
494 sys
.stdout
.write("\n")
495 sys
.stdout
.write("\tData Demand Efficiency:\t\t%s\t%s\n" % (
496 arc
['data_demand_efficiency']['per'],
497 arc
['data_demand_efficiency']['num'],
501 if 'data_prefetch_efficiency' in arc
:
502 sys
.stdout
.write("\tData Prefetch Efficiency:\t%s\t%s\n" % (
503 arc
['data_prefetch_efficiency']['per'],
504 arc
['data_prefetch_efficiency']['num'],
507 sys
.stdout
.write("\n")
509 sys
.stdout
.write("\tCACHE HITS BY CACHE LIST:\n")
510 if 'cache_hits_by_cache_list' in arc
:
511 sys
.stdout
.write("\t Anonymously Used:\t\t%s\t%s\n" % (
512 arc
['cache_hits_by_cache_list']['anonymously_used']['per'],
513 arc
['cache_hits_by_cache_list']['anonymously_used']['num'],
516 sys
.stdout
.write("\t Most Recently Used:\t\t%s\t%s\n" % (
517 arc
['most_recently_used']['per'],
518 arc
['most_recently_used']['num'],
521 sys
.stdout
.write("\t Most Frequently Used:\t\t%s\t%s\n" % (
522 arc
['most_frequently_used']['per'],
523 arc
['most_frequently_used']['num'],
526 sys
.stdout
.write("\t Most Recently Used Ghost:\t%s\t%s\n" % (
527 arc
['most_recently_used_ghost']['per'],
528 arc
['most_recently_used_ghost']['num'],
531 sys
.stdout
.write("\t Most Frequently Used Ghost:\t%s\t%s\n" % (
532 arc
['most_frequently_used_ghost']['per'],
533 arc
['most_frequently_used_ghost']['num'],
537 sys
.stdout
.write("\n\tCACHE HITS BY DATA TYPE:\n")
538 sys
.stdout
.write("\t Demand Data:\t\t\t%s\t%s\n" % (
539 arc
["cache_hits_by_data_type"]['demand_data']['per'],
540 arc
["cache_hits_by_data_type"]['demand_data']['num'],
543 sys
.stdout
.write("\t Prefetch Data:\t\t%s\t%s\n" % (
544 arc
["cache_hits_by_data_type"]['prefetch_data']['per'],
545 arc
["cache_hits_by_data_type"]['prefetch_data']['num'],
548 sys
.stdout
.write("\t Demand Metadata:\t\t%s\t%s\n" % (
549 arc
["cache_hits_by_data_type"]['demand_metadata']['per'],
550 arc
["cache_hits_by_data_type"]['demand_metadata']['num'],
553 sys
.stdout
.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
554 arc
["cache_hits_by_data_type"]['prefetch_metadata']['per'],
555 arc
["cache_hits_by_data_type"]['prefetch_metadata']['num'],
559 sys
.stdout
.write("\n\tCACHE MISSES BY DATA TYPE:\n")
560 sys
.stdout
.write("\t Demand Data:\t\t\t%s\t%s\n" % (
561 arc
["cache_misses_by_data_type"]['demand_data']['per'],
562 arc
["cache_misses_by_data_type"]['demand_data']['num'],
565 sys
.stdout
.write("\t Prefetch Data:\t\t%s\t%s\n" % (
566 arc
["cache_misses_by_data_type"]['prefetch_data']['per'],
567 arc
["cache_misses_by_data_type"]['prefetch_data']['num'],
570 sys
.stdout
.write("\t Demand Metadata:\t\t%s\t%s\n" % (
571 arc
["cache_misses_by_data_type"]['demand_metadata']['per'],
572 arc
["cache_misses_by_data_type"]['demand_metadata']['num'],
575 sys
.stdout
.write("\t Prefetch Metadata:\t\t%s\t%s\n" % (
576 arc
["cache_misses_by_data_type"]['prefetch_metadata']['per'],
577 arc
["cache_misses_by_data_type"]['prefetch_metadata']['num'],
582 def get_l2arc_summary(Kstat
):
585 l2_abort_lowmem
= Kstat
["kstat.zfs.misc.arcstats.l2_abort_lowmem"]
586 l2_cksum_bad
= Kstat
["kstat.zfs.misc.arcstats.l2_cksum_bad"]
587 l2_evict_lock_retry
= Kstat
["kstat.zfs.misc.arcstats.l2_evict_lock_retry"]
588 l2_evict_reading
= Kstat
["kstat.zfs.misc.arcstats.l2_evict_reading"]
589 l2_feeds
= Kstat
["kstat.zfs.misc.arcstats.l2_feeds"]
590 l2_free_on_write
= Kstat
["kstat.zfs.misc.arcstats.l2_free_on_write"]
591 l2_hdr_size
= Kstat
["kstat.zfs.misc.arcstats.l2_hdr_size"]
592 l2_hits
= Kstat
["kstat.zfs.misc.arcstats.l2_hits"]
593 l2_io_error
= Kstat
["kstat.zfs.misc.arcstats.l2_io_error"]
594 l2_misses
= Kstat
["kstat.zfs.misc.arcstats.l2_misses"]
595 l2_rw_clash
= Kstat
["kstat.zfs.misc.arcstats.l2_rw_clash"]
596 l2_size
= Kstat
["kstat.zfs.misc.arcstats.l2_size"]
597 l2_asize
= Kstat
["kstat.zfs.misc.arcstats.l2_asize"]
598 l2_writes_done
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_done"]
599 l2_writes_error
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_error"]
600 l2_writes_sent
= Kstat
["kstat.zfs.misc.arcstats.l2_writes_sent"]
602 l2_access_total
= (l2_hits
+ l2_misses
)
603 output
['l2_health_count'] = (l2_writes_error
+ l2_cksum_bad
+ l2_io_error
)
605 output
['l2_access_total'] = l2_access_total
606 output
['l2_size'] = l2_size
607 output
['l2_asize'] = l2_asize
609 if l2_size
> 0 and l2_access_total
> 0:
611 if output
['l2_health_count'] > 0:
612 output
["health"] = "DEGRADED"
614 output
["health"] = "HEALTHY"
616 output
["low_memory_aborts"] = fHits(l2_abort_lowmem
)
617 output
["free_on_write"] = fHits(l2_free_on_write
)
618 output
["rw_clashes"] = fHits(l2_rw_clash
)
619 output
["bad_checksums"] = fHits(l2_cksum_bad
)
620 output
["io_errors"] = fHits(l2_io_error
)
622 output
["l2_arc_size"] = {}
623 output
["l2_arc_size"]["adative"] = fBytes(l2_size
)
624 output
["l2_arc_size"]["actual"] = {
625 'per': fPerc(l2_asize
, l2_size
),
626 'num': fBytes(l2_asize
)
628 output
["l2_arc_size"]["head_size"] = {
629 'per': fPerc(l2_hdr_size
, l2_size
),
630 'num': fBytes(l2_hdr_size
),
633 output
["l2_arc_evicts"] = {}
634 output
["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry
)
635 output
["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading
)
637 output
['l2_arc_breakdown'] = {}
638 output
['l2_arc_breakdown']['value'] = fHits(l2_access_total
)
639 output
['l2_arc_breakdown']['hit_ratio'] = {
640 'per': fPerc(l2_hits
, l2_access_total
),
641 'num': fHits(l2_hits
),
643 output
['l2_arc_breakdown']['miss_ratio'] = {
644 'per': fPerc(l2_misses
, l2_access_total
),
645 'num': fHits(l2_misses
),
647 output
['l2_arc_breakdown']['feeds'] = fHits(l2_feeds
)
649 output
['l2_arc_buffer'] = {}
651 output
['l2_arc_writes'] = {}
652 output
['l2_writes_done'] = l2_writes_done
653 output
['l2_writes_sent'] = l2_writes_sent
654 if l2_writes_done
!= l2_writes_sent
:
655 output
['l2_arc_writes']['writes_sent'] = {
657 'num': fHits(l2_writes_sent
),
659 output
['l2_arc_writes']['done_ratio'] = {
660 'per': fPerc(l2_writes_done
, l2_writes_sent
),
661 'num': fHits(l2_writes_done
),
663 output
['l2_arc_writes']['error_ratio'] = {
664 'per': fPerc(l2_writes_error
, l2_writes_sent
),
665 'num': fHits(l2_writes_error
),
668 output
['l2_arc_writes']['writes_sent'] = {
670 'num': fHits(l2_writes_sent
),
676 def _l2arc_summary(Kstat
):
678 arc
= get_l2arc_summary(Kstat
)
680 if arc
['l2_size'] > 0 and arc
['l2_access_total'] > 0:
681 sys
.stdout
.write("L2 ARC Summary: ")
682 if arc
['l2_health_count'] > 0:
683 sys
.stdout
.write("(DEGRADED)\n")
685 sys
.stdout
.write("(HEALTHY)\n")
686 sys
.stdout
.write("\tLow Memory Aborts:\t\t\t%s\n" %
687 arc
['low_memory_aborts'])
688 sys
.stdout
.write("\tFree on Write:\t\t\t\t%s\n" % arc
['free_on_write'])
689 sys
.stdout
.write("\tR/W Clashes:\t\t\t\t%s\n" % arc
['rw_clashes'])
690 sys
.stdout
.write("\tBad Checksums:\t\t\t\t%s\n" % arc
['bad_checksums'])
691 sys
.stdout
.write("\tIO Errors:\t\t\t\t%s\n" % arc
['io_errors'])
692 sys
.stdout
.write("\n")
694 sys
.stdout
.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
695 arc
["l2_arc_size"]["adative"])
696 sys
.stdout
.write("\tCompressed:\t\t\t%s\t%s\n" % (
697 arc
["l2_arc_size"]["actual"]["per"],
698 arc
["l2_arc_size"]["actual"]["num"],
701 sys
.stdout
.write("\tHeader Size:\t\t\t%s\t%s\n" % (
702 arc
["l2_arc_size"]["head_size"]["per"],
703 arc
["l2_arc_size"]["head_size"]["num"],
706 sys
.stdout
.write("\n")
708 if arc
["l2_arc_evicts"]['lock_retries'] != '0' or \
709 arc
["l2_arc_evicts"]["reading"] != '0':
710 sys
.stdout
.write("L2 ARC Evicts:\n")
711 sys
.stdout
.write("\tLock Retries:\t\t\t\t%s\n" %
712 arc
["l2_arc_evicts"]['lock_retries'])
713 sys
.stdout
.write("\tUpon Reading:\t\t\t\t%s\n" %
714 arc
["l2_arc_evicts"]["reading"])
715 sys
.stdout
.write("\n")
717 sys
.stdout
.write("L2 ARC Breakdown:\t\t\t\t%s\n" %
718 arc
['l2_arc_breakdown']['value'])
719 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
720 arc
['l2_arc_breakdown']['hit_ratio']['per'],
721 arc
['l2_arc_breakdown']['hit_ratio']['num'],
725 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
726 arc
['l2_arc_breakdown']['miss_ratio']['per'],
727 arc
['l2_arc_breakdown']['miss_ratio']['num'],
731 sys
.stdout
.write("\tFeeds:\t\t\t\t\t%s\n" %
732 arc
['l2_arc_breakdown']['feeds'])
733 sys
.stdout
.write("\n")
735 sys
.stdout
.write("L2 ARC Writes:\n")
736 if arc
['l2_writes_done'] != arc
['l2_writes_sent']:
737 sys
.stdout
.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % (
738 arc
['l2_arc_writes']['writes_sent']['value'],
739 arc
['l2_arc_writes']['writes_sent']['num'],
742 sys
.stdout
.write("\t Done Ratio:\t\t\t%s\t%s\n" % (
743 arc
['l2_arc_writes']['done_ratio']['per'],
744 arc
['l2_arc_writes']['done_ratio']['num'],
747 sys
.stdout
.write("\t Error Ratio:\t\t\t%s\t%s\n" % (
748 arc
['l2_arc_writes']['error_ratio']['per'],
749 arc
['l2_arc_writes']['error_ratio']['num'],
753 sys
.stdout
.write("\tWrites Sent:\t\t\t%s\t%s\n" % (
754 arc
['l2_arc_writes']['writes_sent']['per'],
755 arc
['l2_arc_writes']['writes_sent']['num'],
760 def get_dmu_summary(Kstat
):
763 zfetch_hits
= Kstat
["kstat.zfs.misc.zfetchstats.hits"]
764 zfetch_misses
= Kstat
["kstat.zfs.misc.zfetchstats.misses"]
766 zfetch_access_total
= (zfetch_hits
+ zfetch_misses
)
767 output
['zfetch_access_total'] = zfetch_access_total
769 if zfetch_access_total
> 0:
771 output
['dmu']['efficiency'] = {}
772 output
['dmu']['efficiency']['value'] = fHits(zfetch_access_total
)
773 output
['dmu']['efficiency']['hit_ratio'] = {
774 'per': fPerc(zfetch_hits
, zfetch_access_total
),
775 'num': fHits(zfetch_hits
),
777 output
['dmu']['efficiency']['miss_ratio'] = {
778 'per': fPerc(zfetch_misses
, zfetch_access_total
),
779 'num': fHits(zfetch_misses
),
785 def _dmu_summary(Kstat
):
787 arc
= get_dmu_summary(Kstat
)
789 if arc
['zfetch_access_total'] > 0:
790 sys
.stdout
.write("DMU Prefetch Efficiency:\t\t\t\t\t%s\n" %
791 arc
['dmu']['efficiency']['value'])
792 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
793 arc
['dmu']['efficiency']['hit_ratio']['per'],
794 arc
['dmu']['efficiency']['hit_ratio']['num'],
797 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
798 arc
['dmu']['efficiency']['miss_ratio']['per'],
799 arc
['dmu']['efficiency']['miss_ratio']['num'],
803 sys
.stdout
.write("\n")
806 def get_vdev_summary(Kstat
):
809 vdev_cache_delegations
= \
810 Kstat
["kstat.zfs.misc.vdev_cache_stats.delegations"]
811 vdev_cache_misses
= Kstat
["kstat.zfs.misc.vdev_cache_stats.misses"]
812 vdev_cache_hits
= Kstat
["kstat.zfs.misc.vdev_cache_stats.hits"]
813 vdev_cache_total
= (vdev_cache_misses
+ vdev_cache_hits
+
814 vdev_cache_delegations
)
816 output
['vdev_cache_total'] = vdev_cache_total
818 if vdev_cache_total
> 0:
819 output
['summary'] = fHits(vdev_cache_total
)
820 output
['hit_ratio'] = {
821 'per': fPerc(vdev_cache_hits
, vdev_cache_total
),
822 'num': fHits(vdev_cache_hits
),
824 output
['miss_ratio'] = {
825 'per': fPerc(vdev_cache_misses
, vdev_cache_total
),
826 'num': fHits(vdev_cache_misses
),
828 output
['delegations'] = {
829 'per': fPerc(vdev_cache_delegations
, vdev_cache_total
),
830 'num': fHits(vdev_cache_delegations
),
836 def _vdev_summary(Kstat
):
837 arc
= get_vdev_summary(Kstat
)
839 if arc
['vdev_cache_total'] > 0:
840 sys
.stdout
.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc
['summary'])
841 sys
.stdout
.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
842 arc
['hit_ratio']['per'],
843 arc
['hit_ratio']['num'],
845 sys
.stdout
.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
846 arc
['miss_ratio']['per'],
847 arc
['miss_ratio']['num'],
849 sys
.stdout
.write("\tDelegations:\t\t\t%s\t%s\n" % (
850 arc
['delegations']['per'],
851 arc
['delegations']['num'],
855 def _tunable_summary(Kstat
):
856 global show_tunable_descriptions
857 global alternate_tunable_layout
859 names
= listdir("/sys/module/zfs/parameters/")
863 with
open("/sys/module/zfs/parameters/" + name
) as f
:
865 values
[name
] = value
.strip()
869 if show_tunable_descriptions
:
871 command
= ["/sbin/modinfo", "zfs", "-0"]
872 p
= Popen(command
, stdin
=PIPE
, stdout
=PIPE
,
873 stderr
=PIPE
, shell
=False, close_fds
=True)
876 description_list
= p
.communicate()[0].strip().split('\0')
878 if p
.returncode
== 0:
879 for tunable
in description_list
:
880 if tunable
[0:5] == 'parm:':
881 tunable
= tunable
[5:].strip()
882 name
, description
= tunable
.split(':', 1)
884 description
= "Description unavailable"
885 descriptions
[name
] = description
887 sys
.stderr
.write("%s: '%s' exited with code %i\n" %
888 (sys
.argv
[0], command
[0], p
.returncode
))
889 sys
.stderr
.write("Tunable descriptions will be disabled.\n")
891 sys
.stderr
.write("%s: Cannot run '%s': %s\n" %
892 (sys
.argv
[0], command
[0], e
.strerror
))
893 sys
.stderr
.write("Tunable descriptions will be disabled.\n")
895 sys
.stdout
.write("ZFS Tunable:\n")
900 format
= "\t%-50s%s\n"
901 if alternate_tunable_layout
:
904 if show_tunable_descriptions
and name
in descriptions
:
905 sys
.stdout
.write("\t# %s\n" % descriptions
[name
])
907 sys
.stdout
.write(format
% (name
, values
[name
]))
921 daydate
= time
.strftime("%a %b %d %H:%M:%S %Y")
924 sys
.stdout
.write("ZFS Subsystem Report\t\t\t\t%s" % daydate
)
929 sys
.stdout
.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n")
930 sys
.stdout
.write("\t -h, --help : "
931 "Print this help message and exit\n")
932 sys
.stdout
.write("\t -a, --alternate : "
933 "Show an alternate sysctl layout\n")
934 sys
.stdout
.write("\t -d, --description : "
935 "Show the sysctl descriptions\n")
936 sys
.stdout
.write("\t -p PAGE, --page=PAGE : "
937 "Select a single output page to display,\n")
938 sys
.stdout
.write("\t "
939 "should be an integer between 1 and " +
940 str(len(unSub
)) + "\n\n")
941 sys
.stdout
.write("Examples:\n")
942 sys
.stdout
.write("\tarc_summary.py -a\n")
943 sys
.stdout
.write("\tarc_summary.py -p 4\n")
944 sys
.stdout
.write("\tarc_summary.py -ad\n")
945 sys
.stdout
.write("\tarc_summary.py --page=2\n")
949 global show_tunable_descriptions
950 global alternate_tunable_layout
952 opts
, args
= getopt
.getopt(
953 sys
.argv
[1:], "adp:h", ["alternate", "description", "page=", "help"]
957 for opt
, arg
in opts
:
958 if opt
in ('-a', '--alternate'):
960 if opt
in ('-d', '--description'):
962 if opt
in ('-p', '--page'):
964 if opt
in ('-h', '--help'):
970 alternate_tunable_layout
= 'a' in args
971 show_tunable_descriptions
= 'd' in args
977 pages
.append(unSub
[int(args
['p']) - 1])
979 sys
.stderr
.write('the argument to -p must be between 1 and ' +
980 str(len(unSub
)) + '\n')
991 if __name__
== '__main__':