]>
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 | ||
ea04106b AX |
69 | Kstat = {} |
70 | load_proc_kstats('/proc/spl/kstat/zfs/arcstats', | |
cae5b340 | 71 | 'kstat.zfs.misc.arcstats.') |
ea04106b | 72 | load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats', |
cae5b340 | 73 | 'kstat.zfs.misc.zfetchstats.') |
ea04106b | 74 | load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats', |
cae5b340 | 75 | 'kstat.zfs.misc.vdev_cache_stats.') |
ea04106b AX |
76 | |
77 | return Kstat | |
78 | ||
cae5b340 | 79 | |
ea04106b AX |
80 | def div1(): |
81 | sys.stdout.write("\n") | |
4d815aed | 82 | for i in range(18): |
ea04106b AX |
83 | sys.stdout.write("%s" % "----") |
84 | sys.stdout.write("\n") | |
85 | ||
86 | ||
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 | ||
cae5b340 | 176 | # ARC Misc. |
ea04106b AX |
177 | deleted = Kstat["kstat.zfs.misc.arcstats.deleted"] |
178 | mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"] | |
ea04106b | 179 | |
cae5b340 | 180 | # ARC Misc. |
ea04106b AX |
181 | output["arc_misc"] = {} |
182 | output["arc_misc"]["deleted"] = fHits(deleted) | |
ea04106b AX |
183 | output["arc_misc"]['mutex_miss'] = fHits(mutex_miss) |
184 | output["arc_misc"]['evict_skips'] = fHits(mutex_miss) | |
185 | ||
cae5b340 | 186 | # ARC Sizing |
ea04106b AX |
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 | ||
cae5b340 | 195 | # ARC Sizing |
ea04106b AX |
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 | ||
cae5b340 | 214 | # ARC Hash Breakdown |
ea04106b AX |
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 | ||
cae5b340 | 255 | # ARC Hash Breakdown |
ea04106b AX |
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): | |
cae5b340 | 276 | # ARC Sizing |
ea04106b AX |
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" % | |
cae5b340 | 282 | arc['memory_throttle_count']) |
ea04106b AX |
283 | sys.stdout.write("\n") |
284 | ||
cae5b340 | 285 | # ARC Misc. |
ea04106b AX |
286 | sys.stdout.write("ARC Misc:\n") |
287 | sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted']) | |
ea04106b | 288 | sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" % |
cae5b340 | 289 | arc['arc_misc']['mutex_miss']) |
ea04106b | 290 | sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" % |
cae5b340 | 291 | arc['arc_misc']['mutex_miss']) |
ea04106b AX |
292 | sys.stdout.write("\n") |
293 | ||
cae5b340 | 294 | # ARC Sizing |
ea04106b AX |
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 | ||
cae5b340 | 332 | # ARC Hash Breakdown |
ea04106b AX |
333 | sys.stdout.write("ARC Hash Breakdown:\n") |
334 | sys.stdout.write("\tElements Max:\t\t\t\t%s\n" % | |
cae5b340 | 335 | arc['arc_hash_break']['elements_max']) |
ea04106b AX |
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" % | |
cae5b340 | 342 | arc['arc_hash_break']['collisions']) |
ea04106b | 343 | sys.stdout.write("\tChain Max:\t\t\t\t%s\n" % |
cae5b340 | 344 | arc['arc_hash_break']['chain_max']) |
ea04106b | 345 | sys.stdout.write("\tChains:\t\t\t\t\t%s\n" % |
cae5b340 | 346 | arc['arc_hash_break']['chains']) |
ea04106b AX |
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" % | |
cae5b340 | 476 | arc['total_accesses']) |
ea04106b AX |
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" % | |
cae5b340 | 687 | arc['low_memory_aborts']) |
ea04106b AX |
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" % | |
cae5b340 | 695 | arc["l2_arc_size"]["adative"]) |
ea04106b AX |
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 | ||
cae5b340 AX |
708 | if arc["l2_arc_evicts"]['lock_retries'] != '0' or \ |
709 | arc["l2_arc_evicts"]["reading"] != '0': | |
ea04106b AX |
710 | sys.stdout.write("L2 ARC Evicts:\n") |
711 | sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" % | |
cae5b340 | 712 | arc["l2_arc_evicts"]['lock_retries']) |
ea04106b | 713 | sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" % |
cae5b340 | 714 | arc["l2_arc_evicts"]["reading"]) |
ea04106b AX |
715 | sys.stdout.write("\n") |
716 | ||
717 | sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" % | |
cae5b340 | 718 | arc['l2_arc_breakdown']['value']) |
ea04106b AX |
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" % | |
cae5b340 | 732 | arc['l2_arc_breakdown']['feeds']) |
ea04106b AX |
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 | ||
ea04106b AX |
763 | zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"] |
764 | zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"] | |
ea04106b AX |
765 | |
766 | zfetch_access_total = (zfetch_hits + zfetch_misses) | |
ea04106b AX |
767 | output['zfetch_access_total'] = zfetch_access_total |
768 | ||
769 | if zfetch_access_total > 0: | |
ea04106b AX |
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 | ||
ea04106b AX |
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: | |
cae5b340 AX |
790 | sys.stdout.write("DMU Prefetch Efficiency:\t\t\t\t\t%s\n" % |
791 | arc['dmu']['efficiency']['value']) | |
ea04106b AX |
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 | ||
ea04106b AX |
805 | |
806 | def get_vdev_summary(Kstat): | |
807 | output = {} | |
808 | ||
809 | vdev_cache_delegations = \ | |
cae5b340 | 810 | Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] |
ea04106b AX |
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 + | |
cae5b340 | 814 | vdev_cache_delegations) |
ea04106b AX |
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: | |
cae5b340 AX |
863 | with open("/sys/module/zfs/parameters/" + name) as f: |
864 | value = f.read() | |
ea04106b AX |
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, | |
cae5b340 | 873 | stderr=PIPE, shell=False, close_fds=True) |
ea04106b AX |
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" % | |
cae5b340 | 888 | (sys.argv[0], command[0], p.returncode)) |
ea04106b AX |
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" % | |
cae5b340 | 892 | (sys.argv[0], command[0], e.strerror)) |
ea04106b AX |
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 | ||
4d815aed | 904 | if show_tunable_descriptions and name in descriptions: |
ea04106b AX |
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 : " | |
cae5b340 | 931 | "Print this help message and exit\n") |
ea04106b | 932 | sys.stdout.write("\t -a, --alternate : " |
cae5b340 | 933 | "Show an alternate sysctl layout\n") |
ea04106b | 934 | sys.stdout.write("\t -d, --description : " |
cae5b340 | 935 | "Show the sysctl descriptions\n") |
ea04106b | 936 | sys.stdout.write("\t -p PAGE, --page=PAGE : " |
cae5b340 | 937 | "Select a single output page to display,\n") |
ea04106b | 938 | sys.stdout.write("\t " |
cae5b340 AX |
939 | "should be an integer between 1 and " + |
940 | str(len(unSub)) + "\n\n") | |
ea04106b AX |
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 | ||
cae5b340 | 947 | |
ea04106b AX |
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]) | |
cae5b340 | 978 | except IndexError: |
ea04106b | 979 | sys.stderr.write('the argument to -p must be between 1 and ' + |
cae5b340 | 980 | str(len(unSub)) + '\n') |
ea04106b AX |
981 | sys.exit() |
982 | else: | |
983 | pages = unSub | |
984 | ||
985 | zfs_header() | |
986 | for page in pages: | |
987 | page(Kstat) | |
988 | div2() | |
989 | ||
cae5b340 | 990 | |
ea04106b AX |
991 | if __name__ == '__main__': |
992 | main() |