]> git.proxmox.com Git - mirror_zfs-debian.git/blob - cmd/arc_summary/arc_summary.py
f5aac737b3dcc968da0529a7912e73bb55ad0a42
[mirror_zfs-debian.git] / cmd / arc_summary / arc_summary.py
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
45 import sys
46 import time
47 import getopt
48 import re
49 from os import listdir
50 from subprocess import Popen, PIPE
51 from decimal import Decimal as D
52
53
54 usetunable = True
55 show_tunable_descriptions = False
56 alternate_tunable_layout = False
57 kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M)
58
59
60 def 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
69 Kstat = {}
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.')
76
77 return Kstat
78
79
80 def div1():
81 sys.stdout.write("\n")
82 for i in range(18):
83 sys.stdout.write("%s" % "----")
84 sys.stdout.write("\n")
85
86
87 def div2():
88 sys.stdout.write("\n")
89
90
91 def 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
123 def 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
155 def 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
162 def 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
176 # ARC Misc.
177 deleted = Kstat["kstat.zfs.misc.arcstats.deleted"]
178 mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"]
179
180 # ARC Misc.
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)
185
186 # ARC Sizing
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"]
192
193 target_size_ratio = (target_max_size / target_min_size)
194
195 # ARC Sizing
196 output['arc_sizing'] = {}
197 output['arc_sizing']['arc_size'] = {
198 'per': fPerc(arc_size, target_max_size),
199 'num': fBytes(arc_size),
200 }
201 output['arc_sizing']['target_max_size'] = {
202 'ratio': target_size_ratio,
203 'num': fBytes(target_max_size),
204 }
205 output['arc_sizing']['target_min_size'] = {
206 'per': fPerc(target_min_size, target_max_size),
207 'num': fBytes(target_min_size),
208 }
209 output['arc_sizing']['target_size'] = {
210 'per': fPerc(target_size, target_max_size),
211 'num': fBytes(target_size),
212 }
213
214 # ARC Hash Breakdown
215 output['arc_hash_break'] = {}
216 output['arc_hash_break']['hash_chain_max'] = Kstat[
217 "kstat.zfs.misc.arcstats.hash_chain_max"
218 ]
219 output['arc_hash_break']['hash_chains'] = Kstat[
220 "kstat.zfs.misc.arcstats.hash_chains"
221 ]
222 output['arc_hash_break']['hash_collisions'] = Kstat[
223 "kstat.zfs.misc.arcstats.hash_collisions"
224 ]
225 output['arc_hash_break']['hash_elements'] = Kstat[
226 "kstat.zfs.misc.arcstats.hash_elements"
227 ]
228 output['arc_hash_break']['hash_elements_max'] = Kstat[
229 "kstat.zfs.misc.arcstats.hash_elements_max"
230 ]
231
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),
238 }
239 output['arc_size_break']['frequently_used_cache_size'] = {
240 'per': fPerc(mfu_size, arc_size),
241 'num': fBytes(mfu_size),
242 }
243
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),
249 }
250 output['arc_size_break']['frequently_used_cache_size'] = {
251 'per': fPerc(mfu_size, target_size),
252 'num': fBytes(mfu_size),
253 }
254
255 # ARC Hash Breakdown
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"]
261
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),
267 }
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)
271
272 return output
273
274
275 def _arc_summary(Kstat):
276 # ARC Sizing
277 arc = get_arc_summary(Kstat)
278
279 sys.stdout.write("ARC Summary: (%s)\n" % arc['health'])
280
281 sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" %
282 arc['memory_throttle_count'])
283 sys.stdout.write("\n")
284
285 # ARC Misc.
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")
293
294 # ARC Sizing
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']
298 )
299 )
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'],
303 )
304 )
305
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'],
309 )
310 )
311
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'],
315 )
316 )
317
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'],
322 )
323 )
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'],
327 )
328 )
329
330 sys.stdout.write("\n")
331
332 # ARC Hash Breakdown
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'],
339 )
340 )
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'])
347
348
349 def get_arc_efficiency(Kstat):
350 output = {}
351
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"
358 ]
359 demand_metadata_misses = Kstat[
360 "kstat.zfs.misc.arcstats.demand_metadata_misses"
361 ]
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"
369 ]
370 prefetch_metadata_hits = Kstat[
371 "kstat.zfs.misc.arcstats.prefetch_metadata_hits"
372 ]
373 prefetch_metadata_misses = Kstat[
374 "kstat.zfs.misc.arcstats.prefetch_metadata_misses"
375 ]
376
377 anon_hits = arc_hits - (
378 mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits
379 )
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)
384
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),
389 }
390 output["cache_miss_ratio"] = {
391 'per': fPerc(arc_misses, arc_accesses_total),
392 'num': fHits(arc_misses),
393 }
394 output["actual_hit_ratio"] = {
395 'per': fPerc(real_hits, arc_accesses_total),
396 'num': fHits(real_hits),
397 }
398 output["data_demand_efficiency"] = {
399 'per': fPerc(demand_data_hits, demand_data_total),
400 'num': fHits(demand_data_total),
401 }
402
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),
407 }
408
409 if anon_hits > 0:
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),
414 }
415
416 output["most_recently_used"] = {
417 'per': fPerc(mru_hits, arc_hits),
418 'num': fHits(mru_hits),
419 }
420 output["most_frequently_used"] = {
421 'per': fPerc(mfu_hits, arc_hits),
422 'num': fHits(mfu_hits),
423 }
424 output["most_recently_used_ghost"] = {
425 'per': fPerc(mru_ghost_hits, arc_hits),
426 'num': fHits(mru_ghost_hits),
427 }
428 output["most_frequently_used_ghost"] = {
429 'per': fPerc(mfu_ghost_hits, arc_hits),
430 'num': fHits(mfu_ghost_hits),
431 }
432
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),
437 }
438 output["cache_hits_by_data_type"]["prefetch_data"] = {
439 'per': fPerc(prefetch_data_hits, arc_hits),
440 'num': fHits(prefetch_data_hits),
441 }
442 output["cache_hits_by_data_type"]["demand_metadata"] = {
443 'per': fPerc(demand_metadata_hits, arc_hits),
444 'num': fHits(demand_metadata_hits),
445 }
446 output["cache_hits_by_data_type"]["prefetch_metadata"] = {
447 'per': fPerc(prefetch_metadata_hits, arc_hits),
448 'num': fHits(prefetch_metadata_hits),
449 }
450
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),
455 }
456 output["cache_misses_by_data_type"]["prefetch_data"] = {
457 'per': fPerc(prefetch_data_misses, arc_misses),
458 'num': fHits(prefetch_data_misses),
459 }
460 output["cache_misses_by_data_type"]["demand_metadata"] = {
461 'per': fPerc(demand_metadata_misses, arc_misses),
462 'num': fHits(demand_metadata_misses),
463 }
464 output["cache_misses_by_data_type"]["prefetch_metadata"] = {
465 'per': fPerc(prefetch_metadata_misses, arc_misses),
466 'num': fHits(prefetch_metadata_misses),
467 }
468
469 return output
470
471
472 def _arc_efficiency(Kstat):
473 arc = get_arc_efficiency(Kstat)
474
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'],
480 )
481 )
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'],
485 )
486 )
487
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'],
491 )
492 )
493
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'],
498 )
499 )
500
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'],
505 )
506 )
507 sys.stdout.write("\n")
508
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'],
514 )
515 )
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'],
519 )
520 )
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'],
524 )
525 )
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'],
529 )
530 )
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'],
534 )
535 )
536
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'],
541 )
542 )
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'],
546 )
547 )
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'],
551 )
552 )
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'],
556 )
557 )
558
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'],
563 )
564 )
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'],
568 )
569 )
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'],
573 )
574 )
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'],
578 )
579 )
580
581
582 def get_l2arc_summary(Kstat):
583 output = {}
584
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"]
601
602 l2_access_total = (l2_hits + l2_misses)
603 output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error)
604
605 output['l2_access_total'] = l2_access_total
606 output['l2_size'] = l2_size
607 output['l2_asize'] = l2_asize
608
609 if l2_size > 0 and l2_access_total > 0:
610
611 if output['l2_health_count'] > 0:
612 output["health"] = "DEGRADED"
613 else:
614 output["health"] = "HEALTHY"
615
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)
621
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)
627 }
628 output["l2_arc_size"]["head_size"] = {
629 'per': fPerc(l2_hdr_size, l2_size),
630 'num': fBytes(l2_hdr_size),
631 }
632
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)
636
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),
642 }
643 output['l2_arc_breakdown']['miss_ratio'] = {
644 'per': fPerc(l2_misses, l2_access_total),
645 'num': fHits(l2_misses),
646 }
647 output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds)
648
649 output['l2_arc_buffer'] = {}
650
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'] = {
656 'value': "FAULTED",
657 'num': fHits(l2_writes_sent),
658 }
659 output['l2_arc_writes']['done_ratio'] = {
660 'per': fPerc(l2_writes_done, l2_writes_sent),
661 'num': fHits(l2_writes_done),
662 }
663 output['l2_arc_writes']['error_ratio'] = {
664 'per': fPerc(l2_writes_error, l2_writes_sent),
665 'num': fHits(l2_writes_error),
666 }
667 else:
668 output['l2_arc_writes']['writes_sent'] = {
669 'per': fPerc(100),
670 'num': fHits(l2_writes_sent),
671 }
672
673 return output
674
675
676 def _l2arc_summary(Kstat):
677
678 arc = get_l2arc_summary(Kstat)
679
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")
684 else:
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")
693
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"],
699 )
700 )
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"],
704 )
705 )
706 sys.stdout.write("\n")
707
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")
716
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'],
722 )
723 )
724
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'],
728 )
729 )
730
731 sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" %
732 arc['l2_arc_breakdown']['feeds'])
733 sys.stdout.write("\n")
734
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'],
740 )
741 )
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'],
745 )
746 )
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'],
750 )
751 )
752 else:
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'],
756 )
757 )
758
759
760 def get_dmu_summary(Kstat):
761 output = {}
762
763 zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"]
764 zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"]
765
766 zfetch_access_total = (zfetch_hits + zfetch_misses)
767 output['zfetch_access_total'] = zfetch_access_total
768
769 if zfetch_access_total > 0:
770 output['dmu'] = {}
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),
776 }
777 output['dmu']['efficiency']['miss_ratio'] = {
778 'per': fPerc(zfetch_misses, zfetch_access_total),
779 'num': fHits(zfetch_misses),
780 }
781
782 return output
783
784
785 def _dmu_summary(Kstat):
786
787 arc = get_dmu_summary(Kstat)
788
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'],
795 )
796 )
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'],
800 )
801 )
802
803 sys.stdout.write("\n")
804
805
806 def get_vdev_summary(Kstat):
807 output = {}
808
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)
815
816 output['vdev_cache_total'] = vdev_cache_total
817
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),
823 }
824 output['miss_ratio'] = {
825 'per': fPerc(vdev_cache_misses, vdev_cache_total),
826 'num': fHits(vdev_cache_misses),
827 }
828 output['delegations'] = {
829 'per': fPerc(vdev_cache_delegations, vdev_cache_total),
830 'num': fHits(vdev_cache_delegations),
831 }
832
833 return output
834
835
836 def _vdev_summary(Kstat):
837 arc = get_vdev_summary(Kstat)
838
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'],
844 ))
845 sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
846 arc['miss_ratio']['per'],
847 arc['miss_ratio']['num'],
848 ))
849 sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % (
850 arc['delegations']['per'],
851 arc['delegations']['num'],
852 ))
853
854
855 def _tunable_summary(Kstat):
856 global show_tunable_descriptions
857 global alternate_tunable_layout
858
859 names = listdir("/sys/module/zfs/parameters/")
860
861 values = {}
862 for name in names:
863 with open("/sys/module/zfs/parameters/" + name) as f:
864 value = f.read()
865 values[name] = value.strip()
866
867 descriptions = {}
868
869 if show_tunable_descriptions:
870 try:
871 command = ["/sbin/modinfo", "zfs", "-0"]
872 p = Popen(command, stdin=PIPE, stdout=PIPE,
873 stderr=PIPE, shell=False, close_fds=True)
874 p.wait()
875
876 description_list = p.communicate()[0].strip().split('\0')
877
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)
883 if not description:
884 description = "Description unavailable"
885 descriptions[name] = description
886 else:
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")
890 except OSError as e:
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")
894
895 sys.stdout.write("ZFS Tunable:\n")
896 for name in names:
897 if not name:
898 continue
899
900 format = "\t%-50s%s\n"
901 if alternate_tunable_layout:
902 format = "\t%s=%s\n"
903
904 if show_tunable_descriptions and name in descriptions:
905 sys.stdout.write("\t# %s\n" % descriptions[name])
906
907 sys.stdout.write(format % (name, values[name]))
908
909
910 unSub = [
911 _arc_summary,
912 _arc_efficiency,
913 _l2arc_summary,
914 _dmu_summary,
915 _vdev_summary,
916 _tunable_summary
917 ]
918
919
920 def zfs_header():
921 daydate = time.strftime("%a %b %d %H:%M:%S %Y")
922
923 div1()
924 sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate)
925 div2()
926
927
928 def usage():
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")
946
947
948 def main():
949 global show_tunable_descriptions
950 global alternate_tunable_layout
951
952 opts, args = getopt.getopt(
953 sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"]
954 )
955
956 args = {}
957 for opt, arg in opts:
958 if opt in ('-a', '--alternate'):
959 args['a'] = True
960 if opt in ('-d', '--description'):
961 args['d'] = True
962 if opt in ('-p', '--page'):
963 args['p'] = arg
964 if opt in ('-h', '--help'):
965 usage()
966 sys.exit()
967
968 Kstat = get_Kstat()
969
970 alternate_tunable_layout = 'a' in args
971 show_tunable_descriptions = 'd' in args
972
973 pages = []
974
975 if 'p' in args:
976 try:
977 pages.append(unSub[int(args['p']) - 1])
978 except IndexError:
979 sys.stderr.write('the argument to -p must be between 1 and ' +
980 str(len(unSub)) + '\n')
981 sys.exit()
982 else:
983 pages = unSub
984
985 zfs_header()
986 for page in pages:
987 page(Kstat)
988 div2()
989
990
991 if __name__ == '__main__':
992 main()