]>
Commit | Line | Data |
---|---|---|
ea04106b AX |
1 | #!/usr/bin/python |
2 | # | |
3 | # $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $ | |
4 | # | |
5 | # Copyright (c) 2008 Ben Rockwood <benr@cuddletech.com>, | |
6 | # Copyright (c) 2010 Martin Matuska <mm@FreeBSD.org>, | |
7 | # Copyright (c) 2010-2011 Jason J. Hellenthal <jhell@DataIX.net>, | |
8 | # All rights reserved. | |
9 | # | |
10 | # Redistribution and use in source and binary forms, with or without | |
11 | # modification, are permitted provided that the following conditions | |
12 | # are met: | |
13 | # | |
14 | # 1. Redistributions of source code must retain the above copyright | |
15 | # notice, this list of conditions and the following disclaimer. | |
16 | # 2. Redistributions in binary form must reproduce the above copyright | |
17 | # notice, this list of conditions and the following disclaimer in the | |
18 | # documentation and/or other materials provided with the distribution. | |
19 | # | |
20 | # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
21 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
24 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | # SUCH DAMAGE. | |
31 | # | |
32 | # If you are having troubles when using this script from cron(8) please try | |
33 | # adjusting your PATH before reporting problems. | |
34 | # | |
35 | # /usr/bin & /sbin | |
36 | # | |
37 | # Binaries used are: | |
38 | # | |
39 | # dc(1), kldstat(8), sed(1), sysctl(8) & vmstat(8) | |
40 | # | |
41 | # Binaries that I am working on phasing out are: | |
42 | # | |
43 | # dc(1) & sed(1) | |
44 | ||
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 | Kstats = [ | |
70 | "hw.pagesize", | |
71 | "hw.physmem", | |
72 | "kern.maxusers", | |
73 | "vm.kmem_map_free", | |
74 | "vm.kmem_map_size", | |
75 | "vm.kmem_size", | |
76 | "vm.kmem_size_max", | |
77 | "vm.kmem_size_min", | |
78 | "vm.kmem_size_scale", | |
79 | "vm.stats", | |
80 | "vm.swap_total", | |
81 | "vm.swap_reserved", | |
82 | "kstat.zfs", | |
83 | "vfs.zfs" | |
84 | ] | |
85 | Kstat = {} | |
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.') | |
92 | ||
93 | return Kstat | |
94 | ||
95 | def div1(): | |
96 | sys.stdout.write("\n") | |
4d815aed | 97 | for i in range(18): |
ea04106b AX |
98 | sys.stdout.write("%s" % "----") |
99 | sys.stdout.write("\n") | |
100 | ||
101 | ||
102 | def div2(): | |
103 | sys.stdout.write("\n") | |
104 | ||
105 | ||
106 | def fBytes(Bytes=0, Decimal=2): | |
107 | kbytes = (2 ** 10) | |
108 | mbytes = (2 ** 20) | |
109 | gbytes = (2 ** 30) | |
110 | tbytes = (2 ** 40) | |
111 | pbytes = (2 ** 50) | |
112 | ebytes = (2 ** 60) | |
113 | zbytes = (2 ** 70) | |
114 | ybytes = (2 ** 80) | |
115 | ||
116 | if Bytes >= ybytes: | |
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" | |
132 | elif Bytes == 0: | |
133 | return str("%d" % 0) + "\tBytes" | |
134 | else: | |
135 | return str("%d" % Bytes) + "\tBytes" | |
136 | ||
137 | ||
138 | def fHits(Hits=0, Decimal=2): | |
139 | khits = (10 ** 3) | |
140 | mhits = (10 ** 6) | |
141 | bhits = (10 ** 9) | |
142 | thits = (10 ** 12) | |
143 | qhits = (10 ** 15) | |
144 | Qhits = (10 ** 18) | |
145 | shits = (10 ** 21) | |
146 | Shits = (10 ** 24) | |
147 | ||
148 | if Hits >= Shits: | |
149 | return str("%0." + str(Decimal) + "f") % (Hits / Shits) + "S" | |
150 | elif Hits >= shits: | |
151 | return str("%0." + str(Decimal) + "f") % (Hits / shits) + "s" | |
152 | elif Hits >= Qhits: | |
153 | return str("%0." + str(Decimal) + "f") % (Hits / Qhits) + "Q" | |
154 | elif Hits >= qhits: | |
155 | return str("%0." + str(Decimal) + "f") % (Hits / qhits) + "q" | |
156 | elif Hits >= thits: | |
157 | return str("%0." + str(Decimal) + "f") % (Hits / thits) + "t" | |
158 | elif Hits >= bhits: | |
159 | return str("%0." + str(Decimal) + "f") % (Hits / bhits) + "b" | |
160 | elif Hits >= mhits: | |
161 | return str("%0." + str(Decimal) + "f") % (Hits / mhits) + "m" | |
162 | elif Hits >= khits: | |
163 | return str("%0." + str(Decimal) + "f") % (Hits / khits) + "k" | |
164 | elif Hits == 0: | |
165 | return str("%d" % 0) | |
166 | else: | |
167 | return str("%d" % Hits) | |
168 | ||
169 | ||
170 | def fPerc(lVal=0, rVal=0, Decimal=2): | |
171 | if rVal > 0: | |
172 | return str("%0." + str(Decimal) + "f") % (100 * (lVal / rVal)) + "%" | |
173 | else: | |
174 | return str("%0." + str(Decimal) + "f") % 100 + "%" | |
175 | ||
176 | ||
177 | def get_arc_summary(Kstat): | |
178 | ||
179 | output = {} | |
180 | memory_throttle_count = Kstat[ | |
181 | "kstat.zfs.misc.arcstats.memory_throttle_count" | |
182 | ] | |
183 | ||
184 | if memory_throttle_count > 0: | |
185 | output['health'] = 'THROTTLED' | |
186 | else: | |
187 | output['health'] = 'HEALTHY' | |
188 | ||
189 | output['memory_throttle_count'] = fHits(memory_throttle_count) | |
190 | ||
191 | ### ARC Misc. ### | |
192 | deleted = Kstat["kstat.zfs.misc.arcstats.deleted"] | |
193 | mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"] | |
ea04106b AX |
194 | |
195 | ### ARC Misc. ### | |
196 | output["arc_misc"] = {} | |
197 | output["arc_misc"]["deleted"] = fHits(deleted) | |
ea04106b AX |
198 | output["arc_misc"]['mutex_miss'] = fHits(mutex_miss) |
199 | output["arc_misc"]['evict_skips'] = fHits(mutex_miss) | |
200 | ||
201 | ### ARC Sizing ### | |
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"] | |
207 | ||
208 | target_size_ratio = (target_max_size / target_min_size) | |
209 | ||
210 | ### ARC Sizing ### | |
211 | output['arc_sizing'] = {} | |
212 | output['arc_sizing']['arc_size'] = { | |
213 | 'per': fPerc(arc_size, target_max_size), | |
214 | 'num': fBytes(arc_size), | |
215 | } | |
216 | output['arc_sizing']['target_max_size'] = { | |
217 | 'ratio': target_size_ratio, | |
218 | 'num': fBytes(target_max_size), | |
219 | } | |
220 | output['arc_sizing']['target_min_size'] = { | |
221 | 'per': fPerc(target_min_size, target_max_size), | |
222 | 'num': fBytes(target_min_size), | |
223 | } | |
224 | output['arc_sizing']['target_size'] = { | |
225 | 'per': fPerc(target_size, target_max_size), | |
226 | 'num': fBytes(target_size), | |
227 | } | |
228 | ||
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" | |
233 | ] | |
234 | output['arc_hash_break']['hash_chains'] = Kstat[ | |
235 | "kstat.zfs.misc.arcstats.hash_chains" | |
236 | ] | |
237 | output['arc_hash_break']['hash_collisions'] = Kstat[ | |
238 | "kstat.zfs.misc.arcstats.hash_collisions" | |
239 | ] | |
240 | output['arc_hash_break']['hash_elements'] = Kstat[ | |
241 | "kstat.zfs.misc.arcstats.hash_elements" | |
242 | ] | |
243 | output['arc_hash_break']['hash_elements_max'] = Kstat[ | |
244 | "kstat.zfs.misc.arcstats.hash_elements_max" | |
245 | ] | |
246 | ||
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), | |
253 | } | |
254 | output['arc_size_break']['frequently_used_cache_size'] = { | |
255 | 'per': fPerc(mfu_size, arc_size), | |
256 | 'num': fBytes(mfu_size), | |
257 | } | |
258 | ||
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), | |
264 | } | |
265 | output['arc_size_break']['frequently_used_cache_size'] = { | |
266 | 'per': fPerc(mfu_size, target_size), | |
267 | 'num': fBytes(mfu_size), | |
268 | } | |
269 | ||
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"] | |
276 | ||
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), | |
282 | } | |
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) | |
286 | ||
287 | return output | |
288 | ||
289 | ||
290 | def _arc_summary(Kstat): | |
291 | ### ARC Sizing ### | |
292 | arc = get_arc_summary(Kstat) | |
293 | ||
294 | sys.stdout.write("ARC Summary: (%s)\n" % arc['health']) | |
295 | ||
296 | sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % | |
297 | arc['memory_throttle_count']) | |
298 | sys.stdout.write("\n") | |
299 | ||
300 | ### ARC Misc. ### | |
301 | sys.stdout.write("ARC Misc:\n") | |
302 | sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted']) | |
ea04106b AX |
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") | |
308 | ||
309 | ### ARC Sizing ### | |
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'] | |
313 | ) | |
314 | ) | |
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'], | |
318 | ) | |
319 | ) | |
320 | ||
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'], | |
324 | ) | |
325 | ) | |
326 | ||
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'], | |
330 | ) | |
331 | ) | |
332 | ||
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'], | |
337 | ) | |
338 | ) | |
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'], | |
342 | ) | |
343 | ) | |
344 | ||
345 | sys.stdout.write("\n") | |
346 | ||
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'], | |
354 | ) | |
355 | ) | |
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']) | |
362 | ||
363 | ||
364 | def get_arc_efficiency(Kstat): | |
365 | output = {} | |
366 | ||
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" | |
373 | ] | |
374 | demand_metadata_misses = Kstat[ | |
375 | "kstat.zfs.misc.arcstats.demand_metadata_misses" | |
376 | ] | |
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" | |
384 | ] | |
385 | prefetch_metadata_hits = Kstat[ | |
386 | "kstat.zfs.misc.arcstats.prefetch_metadata_hits" | |
387 | ] | |
388 | prefetch_metadata_misses = Kstat[ | |
389 | "kstat.zfs.misc.arcstats.prefetch_metadata_misses" | |
390 | ] | |
391 | ||
392 | anon_hits = arc_hits - ( | |
393 | mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits | |
394 | ) | |
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) | |
399 | ||
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), | |
404 | } | |
405 | output["cache_miss_ratio"] = { | |
406 | 'per': fPerc(arc_misses, arc_accesses_total), | |
407 | 'num': fHits(arc_misses), | |
408 | } | |
409 | output["actual_hit_ratio"] = { | |
410 | 'per': fPerc(real_hits, arc_accesses_total), | |
411 | 'num': fHits(real_hits), | |
412 | } | |
413 | output["data_demand_efficiency"] = { | |
414 | 'per': fPerc(demand_data_hits, demand_data_total), | |
415 | 'num': fHits(demand_data_total), | |
416 | } | |
417 | ||
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), | |
422 | } | |
423 | ||
424 | if anon_hits > 0: | |
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), | |
429 | } | |
430 | ||
431 | output["most_recently_used"] = { | |
432 | 'per': fPerc(mru_hits, arc_hits), | |
433 | 'num': fHits(mru_hits), | |
434 | } | |
435 | output["most_frequently_used"] = { | |
436 | 'per': fPerc(mfu_hits, arc_hits), | |
437 | 'num': fHits(mfu_hits), | |
438 | } | |
439 | output["most_recently_used_ghost"] = { | |
440 | 'per': fPerc(mru_ghost_hits, arc_hits), | |
441 | 'num': fHits(mru_ghost_hits), | |
442 | } | |
443 | output["most_frequently_used_ghost"] = { | |
444 | 'per': fPerc(mfu_ghost_hits, arc_hits), | |
445 | 'num': fHits(mfu_ghost_hits), | |
446 | } | |
447 | ||
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), | |
452 | } | |
453 | output["cache_hits_by_data_type"]["prefetch_data"] = { | |
454 | 'per': fPerc(prefetch_data_hits, arc_hits), | |
455 | 'num': fHits(prefetch_data_hits), | |
456 | } | |
457 | output["cache_hits_by_data_type"]["demand_metadata"] = { | |
458 | 'per': fPerc(demand_metadata_hits, arc_hits), | |
459 | 'num': fHits(demand_metadata_hits), | |
460 | } | |
461 | output["cache_hits_by_data_type"]["prefetch_metadata"] = { | |
462 | 'per': fPerc(prefetch_metadata_hits, arc_hits), | |
463 | 'num': fHits(prefetch_metadata_hits), | |
464 | } | |
465 | ||
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), | |
470 | } | |
471 | output["cache_misses_by_data_type"]["prefetch_data"] = { | |
472 | 'per': fPerc(prefetch_data_misses, arc_misses), | |
473 | 'num': fHits(prefetch_data_misses), | |
474 | } | |
475 | output["cache_misses_by_data_type"]["demand_metadata"] = { | |
476 | 'per': fPerc(demand_metadata_misses, arc_misses), | |
477 | 'num': fHits(demand_metadata_misses), | |
478 | } | |
479 | output["cache_misses_by_data_type"]["prefetch_metadata"] = { | |
480 | 'per': fPerc(prefetch_metadata_misses, arc_misses), | |
481 | 'num': fHits(prefetch_metadata_misses), | |
482 | } | |
483 | ||
484 | return output | |
485 | ||
486 | ||
487 | def _arc_efficiency(Kstat): | |
488 | arc = get_arc_efficiency(Kstat) | |
489 | ||
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'], | |
495 | ) | |
496 | ) | |
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'], | |
500 | ) | |
501 | ) | |
502 | ||
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'], | |
506 | ) | |
507 | ) | |
508 | ||
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'], | |
513 | ) | |
514 | ) | |
515 | ||
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'], | |
520 | ) | |
521 | ) | |
522 | sys.stdout.write("\n") | |
523 | ||
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'], | |
529 | ) | |
530 | ) | |
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'], | |
534 | ) | |
535 | ) | |
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'], | |
539 | ) | |
540 | ) | |
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'], | |
544 | ) | |
545 | ) | |
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'], | |
549 | ) | |
550 | ) | |
551 | ||
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'], | |
556 | ) | |
557 | ) | |
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'], | |
561 | ) | |
562 | ) | |
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'], | |
566 | ) | |
567 | ) | |
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'], | |
571 | ) | |
572 | ) | |
573 | ||
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'], | |
578 | ) | |
579 | ) | |
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'], | |
583 | ) | |
584 | ) | |
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'], | |
588 | ) | |
589 | ) | |
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'], | |
593 | ) | |
594 | ) | |
595 | ||
596 | ||
597 | def get_l2arc_summary(Kstat): | |
598 | output = {} | |
599 | ||
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"] | |
616 | ||
617 | l2_access_total = (l2_hits + l2_misses) | |
618 | output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error) | |
619 | ||
620 | output['l2_access_total'] = l2_access_total | |
621 | output['l2_size'] = l2_size | |
622 | output['l2_asize'] = l2_asize | |
623 | ||
624 | if l2_size > 0 and l2_access_total > 0: | |
625 | ||
626 | if output['l2_health_count'] > 0: | |
627 | output["health"] = "DEGRADED" | |
628 | else: | |
629 | output["health"] = "HEALTHY" | |
630 | ||
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) | |
636 | ||
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) | |
642 | } | |
643 | output["l2_arc_size"]["head_size"] = { | |
644 | 'per': fPerc(l2_hdr_size, l2_size), | |
645 | 'num': fBytes(l2_hdr_size), | |
646 | } | |
647 | ||
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) | |
651 | ||
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), | |
657 | } | |
658 | output['l2_arc_breakdown']['miss_ratio'] = { | |
659 | 'per': fPerc(l2_misses, l2_access_total), | |
660 | 'num': fHits(l2_misses), | |
661 | } | |
662 | output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds) | |
663 | ||
664 | output['l2_arc_buffer'] = {} | |
665 | ||
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'] = { | |
671 | 'value': "FAULTED", | |
672 | 'num': fHits(l2_writes_sent), | |
673 | } | |
674 | output['l2_arc_writes']['done_ratio'] = { | |
675 | 'per': fPerc(l2_writes_done, l2_writes_sent), | |
676 | 'num': fHits(l2_writes_done), | |
677 | } | |
678 | output['l2_arc_writes']['error_ratio'] = { | |
679 | 'per': fPerc(l2_writes_error, l2_writes_sent), | |
680 | 'num': fHits(l2_writes_error), | |
681 | } | |
682 | else: | |
683 | output['l2_arc_writes']['writes_sent'] = { | |
684 | 'per': fPerc(100), | |
685 | 'num': fHits(l2_writes_sent), | |
686 | } | |
687 | ||
688 | return output | |
689 | ||
690 | ||
691 | def _l2arc_summary(Kstat): | |
692 | ||
693 | arc = get_l2arc_summary(Kstat) | |
694 | ||
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") | |
699 | else: | |
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") | |
708 | ||
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"], | |
714 | ) | |
715 | ) | |
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"], | |
719 | ) | |
720 | ) | |
721 | sys.stdout.write("\n") | |
722 | ||
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") | |
731 | ||
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'], | |
737 | ) | |
738 | ) | |
739 | ||
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'], | |
743 | ) | |
744 | ) | |
745 | ||
746 | sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % | |
747 | arc['l2_arc_breakdown']['feeds']) | |
748 | sys.stdout.write("\n") | |
749 | ||
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'], | |
755 | ) | |
756 | ) | |
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'], | |
760 | ) | |
761 | ) | |
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'], | |
765 | ) | |
766 | ) | |
767 | else: | |
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'], | |
771 | ) | |
772 | ) | |
773 | ||
774 | ||
775 | def get_dmu_summary(Kstat): | |
776 | output = {} | |
777 | ||
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"] | |
793 | ||
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 | |
802 | ||
803 | if zfetch_access_total > 0: | |
804 | ||
805 | output['file_level_prefetch'] = {} | |
806 | if zfetch_health_count > 0: | |
807 | output['file_level_prefetch']['health'] = 'DEGRADED' | |
808 | else: | |
809 | output['file_level_prefetch']['health'] = 'HEALTHY' | |
810 | ||
811 | output['dmu'] = {} | |
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), | |
817 | } | |
818 | output['dmu']['efficiency']['miss_ratio'] = { | |
819 | 'per': fPerc(zfetch_misses, zfetch_access_total), | |
820 | 'num': fHits(zfetch_misses), | |
821 | } | |
822 | ||
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), | |
828 | } | |
829 | output['dmu']['colinear']['miss_ratio'] = { | |
830 | 'per': fPerc(zfetch_colinear_misses, zfetch_colinear_total), | |
831 | 'num': fHits(zfetch_colinear_misses), | |
832 | } | |
833 | ||
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), | |
839 | } | |
840 | output['dmu']['stride']['miss_ratio'] = { | |
841 | 'per': fPerc(zfetch_stride_misses, zfetch_stride_total), | |
842 | 'num': fHits(zfetch_stride_misses), | |
843 | } | |
844 | ||
845 | output['dmu_misc'] = {} | |
846 | if zfetch_health_count > 0: | |
847 | output['dmu_misc']['status'] = "FAULTED" | |
848 | else: | |
849 | output['dmu_misc']['status'] = "" | |
850 | ||
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), | |
856 | } | |
857 | output['dmu_misc']['reclaim']['failure'] = { | |
858 | 'per': fPerc(zfetch_reclaim_failures, zfetch_reclaim_total), | |
859 | 'num': fHits(zfetch_reclaim_failures), | |
860 | } | |
861 | ||
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), | |
867 | } | |
868 | output['dmu_misc']['streams']['neg_resets'] = { | |
869 | 'per': fPerc(zfetch_streams_noresets, zfetch_streams_total), | |
870 | 'num': fHits(zfetch_streams_noresets), | |
871 | } | |
872 | output['dmu_misc']['streams']['bogus'] = fHits(zfetch_bogus_streams) | |
873 | ||
874 | return output | |
875 | ||
876 | ||
877 | def _dmu_summary(Kstat): | |
878 | ||
879 | arc = get_dmu_summary(Kstat) | |
880 | ||
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") | |
885 | ||
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'], | |
891 | ) | |
892 | ) | |
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'], | |
896 | ) | |
897 | ) | |
898 | ||
899 | sys.stdout.write("\n") | |
900 | ||
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'], | |
906 | ) | |
907 | ) | |
908 | ||
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'], | |
912 | ) | |
913 | ) | |
914 | ||
915 | sys.stdout.write("\n") | |
916 | ||
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'], | |
922 | ) | |
923 | ) | |
924 | ||
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'], | |
928 | ) | |
929 | ) | |
930 | ||
931 | sys.stdout.write("\n") | |
932 | sys.stdout.write("DMU Misc: %s\n" % arc['dmu_misc']['status']) | |
933 | ||
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'], | |
939 | ) | |
940 | ) | |
941 | ||
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'], | |
945 | ) | |
946 | ) | |
947 | ||
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'], | |
953 | ) | |
954 | ) | |
955 | ||
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'], | |
959 | ) | |
960 | ) | |
961 | ||
962 | sys.stdout.write("\t Bogus:\t\t\t\t%s\n" % | |
963 | arc['dmu_misc']['streams']['bogus']) | |
964 | ||
965 | ||
966 | def get_vdev_summary(Kstat): | |
967 | output = {} | |
968 | ||
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) | |
975 | ||
976 | output['vdev_cache_total'] = vdev_cache_total | |
977 | ||
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), | |
983 | } | |
984 | output['miss_ratio'] = { | |
985 | 'per': fPerc(vdev_cache_misses, vdev_cache_total), | |
986 | 'num': fHits(vdev_cache_misses), | |
987 | } | |
988 | output['delegations'] = { | |
989 | 'per': fPerc(vdev_cache_delegations, vdev_cache_total), | |
990 | 'num': fHits(vdev_cache_delegations), | |
991 | } | |
992 | ||
993 | return output | |
994 | ||
995 | ||
996 | def _vdev_summary(Kstat): | |
997 | arc = get_vdev_summary(Kstat) | |
998 | ||
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'], | |
1004 | )) | |
1005 | sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( | |
1006 | arc['miss_ratio']['per'], | |
1007 | arc['miss_ratio']['num'], | |
1008 | )) | |
1009 | sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % ( | |
1010 | arc['delegations']['per'], | |
1011 | arc['delegations']['num'], | |
1012 | )) | |
1013 | ||
1014 | ||
1015 | def _tunable_summary(Kstat): | |
1016 | global show_tunable_descriptions | |
1017 | global alternate_tunable_layout | |
1018 | ||
1019 | names = listdir("/sys/module/zfs/parameters/") | |
1020 | ||
1021 | values = {} | |
1022 | for name in names: | |
1023 | with open("/sys/module/zfs/parameters/" + name) as f: value = f.read() | |
1024 | values[name] = value.strip() | |
1025 | ||
1026 | descriptions = {} | |
1027 | ||
1028 | if show_tunable_descriptions: | |
1029 | try: | |
1030 | command = ["/sbin/modinfo", "zfs", "-0"] | |
1031 | p = Popen(command, stdin=PIPE, stdout=PIPE, | |
1032 | stderr=PIPE, shell=False, close_fds=True) | |
1033 | p.wait() | |
1034 | ||
1035 | description_list = p.communicate()[0].strip().split('\0') | |
1036 | ||
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) | |
1042 | if not description: | |
1043 | description = "Description unavailable" | |
1044 | descriptions[name] = description | |
1045 | else: | |
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") | |
1053 | ||
1054 | sys.stdout.write("ZFS Tunable:\n") | |
1055 | for name in names: | |
1056 | if not name: | |
1057 | continue | |
1058 | ||
1059 | format = "\t%-50s%s\n" | |
1060 | if alternate_tunable_layout: | |
1061 | format = "\t%s=%s\n" | |
1062 | ||
4d815aed | 1063 | if show_tunable_descriptions and name in descriptions: |
ea04106b AX |
1064 | sys.stdout.write("\t# %s\n" % descriptions[name]) |
1065 | ||
1066 | sys.stdout.write(format % (name, values[name])) | |
1067 | ||
1068 | ||
1069 | unSub = [ | |
1070 | _arc_summary, | |
1071 | _arc_efficiency, | |
1072 | _l2arc_summary, | |
1073 | _dmu_summary, | |
1074 | _vdev_summary, | |
1075 | _tunable_summary | |
1076 | ] | |
1077 | ||
1078 | ||
1079 | def zfs_header(): | |
1080 | daydate = time.strftime("%a %b %d %H:%M:%S %Y") | |
1081 | ||
1082 | div1() | |
1083 | sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate) | |
1084 | div2() | |
1085 | ||
1086 | ||
1087 | def usage(): | |
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") | |
1104 | ||
1105 | def main(): | |
1106 | global show_tunable_descriptions | |
1107 | global alternate_tunable_layout | |
1108 | ||
1109 | opts, args = getopt.getopt( | |
1110 | sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"] | |
1111 | ) | |
1112 | ||
1113 | args = {} | |
1114 | for opt, arg in opts: | |
1115 | if opt in ('-a', '--alternate'): | |
1116 | args['a'] = True | |
1117 | if opt in ('-d', '--description'): | |
1118 | args['d'] = True | |
1119 | if opt in ('-p', '--page'): | |
1120 | args['p'] = arg | |
1121 | if opt in ('-h', '--help'): | |
1122 | usage() | |
1123 | sys.exit() | |
1124 | ||
1125 | Kstat = get_Kstat() | |
1126 | ||
1127 | alternate_tunable_layout = 'a' in args | |
1128 | show_tunable_descriptions = 'd' in args | |
1129 | ||
1130 | pages = [] | |
1131 | ||
1132 | if 'p' in args: | |
1133 | try: | |
1134 | pages.append(unSub[int(args['p']) - 1]) | |
4d815aed | 1135 | except IndexError as e: |
ea04106b AX |
1136 | sys.stderr.write('the argument to -p must be between 1 and ' + |
1137 | str(len(unSub)) + '\n') | |
1138 | sys.exit() | |
1139 | else: | |
1140 | pages = unSub | |
1141 | ||
1142 | zfs_header() | |
1143 | for page in pages: | |
1144 | page(Kstat) | |
1145 | div2() | |
1146 | ||
1147 | if __name__ == '__main__': | |
1148 | main() |