]>
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 | 187 | arc_size = Kstat["kstat.zfs.misc.arcstats.size"] |
41d74433 AX |
188 | mru_size = Kstat["kstat.zfs.misc.arcstats.mru_size"] |
189 | mfu_size = Kstat["kstat.zfs.misc.arcstats.mfu_size"] | |
ea04106b AX |
190 | target_max_size = Kstat["kstat.zfs.misc.arcstats.c_max"] |
191 | target_min_size = Kstat["kstat.zfs.misc.arcstats.c_min"] | |
192 | target_size = Kstat["kstat.zfs.misc.arcstats.c"] | |
193 | ||
194 | target_size_ratio = (target_max_size / target_min_size) | |
195 | ||
cae5b340 | 196 | # ARC Sizing |
ea04106b AX |
197 | output['arc_sizing'] = {} |
198 | output['arc_sizing']['arc_size'] = { | |
199 | 'per': fPerc(arc_size, target_max_size), | |
200 | 'num': fBytes(arc_size), | |
201 | } | |
202 | output['arc_sizing']['target_max_size'] = { | |
203 | 'ratio': target_size_ratio, | |
204 | 'num': fBytes(target_max_size), | |
205 | } | |
206 | output['arc_sizing']['target_min_size'] = { | |
207 | 'per': fPerc(target_min_size, target_max_size), | |
208 | 'num': fBytes(target_min_size), | |
209 | } | |
210 | output['arc_sizing']['target_size'] = { | |
211 | 'per': fPerc(target_size, target_max_size), | |
212 | 'num': fBytes(target_size), | |
213 | } | |
214 | ||
cae5b340 | 215 | # ARC Hash Breakdown |
ea04106b AX |
216 | output['arc_hash_break'] = {} |
217 | output['arc_hash_break']['hash_chain_max'] = Kstat[ | |
218 | "kstat.zfs.misc.arcstats.hash_chain_max" | |
219 | ] | |
220 | output['arc_hash_break']['hash_chains'] = Kstat[ | |
221 | "kstat.zfs.misc.arcstats.hash_chains" | |
222 | ] | |
223 | output['arc_hash_break']['hash_collisions'] = Kstat[ | |
224 | "kstat.zfs.misc.arcstats.hash_collisions" | |
225 | ] | |
226 | output['arc_hash_break']['hash_elements'] = Kstat[ | |
227 | "kstat.zfs.misc.arcstats.hash_elements" | |
228 | ] | |
229 | output['arc_hash_break']['hash_elements_max'] = Kstat[ | |
230 | "kstat.zfs.misc.arcstats.hash_elements_max" | |
231 | ] | |
232 | ||
233 | output['arc_size_break'] = {} | |
41d74433 AX |
234 | output['arc_size_break']['recently_used_cache_size'] = { |
235 | 'per': fPerc(mru_size, mru_size + mfu_size), | |
236 | 'num': fBytes(mru_size), | |
237 | } | |
238 | output['arc_size_break']['frequently_used_cache_size'] = { | |
239 | 'per': fPerc(mfu_size, mru_size + mfu_size), | |
240 | 'num': fBytes(mfu_size), | |
241 | } | |
ea04106b | 242 | |
cae5b340 | 243 | # ARC Hash Breakdown |
ea04106b AX |
244 | hash_chain_max = Kstat["kstat.zfs.misc.arcstats.hash_chain_max"] |
245 | hash_chains = Kstat["kstat.zfs.misc.arcstats.hash_chains"] | |
246 | hash_collisions = Kstat["kstat.zfs.misc.arcstats.hash_collisions"] | |
247 | hash_elements = Kstat["kstat.zfs.misc.arcstats.hash_elements"] | |
248 | hash_elements_max = Kstat["kstat.zfs.misc.arcstats.hash_elements_max"] | |
249 | ||
250 | output['arc_hash_break'] = {} | |
251 | output['arc_hash_break']['elements_max'] = fHits(hash_elements_max) | |
252 | output['arc_hash_break']['elements_current'] = { | |
253 | 'per': fPerc(hash_elements, hash_elements_max), | |
254 | 'num': fHits(hash_elements), | |
255 | } | |
256 | output['arc_hash_break']['collisions'] = fHits(hash_collisions) | |
257 | output['arc_hash_break']['chain_max'] = fHits(hash_chain_max) | |
258 | output['arc_hash_break']['chains'] = fHits(hash_chains) | |
259 | ||
260 | return output | |
261 | ||
262 | ||
263 | def _arc_summary(Kstat): | |
cae5b340 | 264 | # ARC Sizing |
ea04106b AX |
265 | arc = get_arc_summary(Kstat) |
266 | ||
267 | sys.stdout.write("ARC Summary: (%s)\n" % arc['health']) | |
268 | ||
269 | sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" % | |
cae5b340 | 270 | arc['memory_throttle_count']) |
ea04106b AX |
271 | sys.stdout.write("\n") |
272 | ||
cae5b340 | 273 | # ARC Misc. |
ea04106b AX |
274 | sys.stdout.write("ARC Misc:\n") |
275 | sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted']) | |
ea04106b | 276 | sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" % |
cae5b340 | 277 | arc['arc_misc']['mutex_miss']) |
ea04106b | 278 | sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" % |
cae5b340 | 279 | arc['arc_misc']['mutex_miss']) |
ea04106b AX |
280 | sys.stdout.write("\n") |
281 | ||
cae5b340 | 282 | # ARC Sizing |
ea04106b AX |
283 | sys.stdout.write("ARC Size:\t\t\t\t%s\t%s\n" % ( |
284 | arc['arc_sizing']['arc_size']['per'], | |
285 | arc['arc_sizing']['arc_size']['num'] | |
286 | ) | |
287 | ) | |
288 | sys.stdout.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % ( | |
289 | arc['arc_sizing']['target_size']['per'], | |
290 | arc['arc_sizing']['target_size']['num'], | |
291 | ) | |
292 | ) | |
293 | ||
294 | sys.stdout.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % ( | |
295 | arc['arc_sizing']['target_min_size']['per'], | |
296 | arc['arc_sizing']['target_min_size']['num'], | |
297 | ) | |
298 | ) | |
299 | ||
300 | sys.stdout.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % ( | |
301 | arc['arc_sizing']['target_max_size']['ratio'], | |
302 | arc['arc_sizing']['target_max_size']['num'], | |
303 | ) | |
304 | ) | |
305 | ||
306 | sys.stdout.write("\nARC Size Breakdown:\n") | |
307 | sys.stdout.write("\tRecently Used Cache Size:\t%s\t%s\n" % ( | |
308 | arc['arc_size_break']['recently_used_cache_size']['per'], | |
309 | arc['arc_size_break']['recently_used_cache_size']['num'], | |
310 | ) | |
311 | ) | |
312 | sys.stdout.write("\tFrequently Used Cache Size:\t%s\t%s\n" % ( | |
313 | arc['arc_size_break']['frequently_used_cache_size']['per'], | |
314 | arc['arc_size_break']['frequently_used_cache_size']['num'], | |
315 | ) | |
316 | ) | |
317 | ||
318 | sys.stdout.write("\n") | |
319 | ||
cae5b340 | 320 | # ARC Hash Breakdown |
ea04106b AX |
321 | sys.stdout.write("ARC Hash Breakdown:\n") |
322 | sys.stdout.write("\tElements Max:\t\t\t\t%s\n" % | |
cae5b340 | 323 | arc['arc_hash_break']['elements_max']) |
ea04106b AX |
324 | sys.stdout.write("\tElements Current:\t\t%s\t%s\n" % ( |
325 | arc['arc_hash_break']['elements_current']['per'], | |
326 | arc['arc_hash_break']['elements_current']['num'], | |
327 | ) | |
328 | ) | |
329 | sys.stdout.write("\tCollisions:\t\t\t\t%s\n" % | |
cae5b340 | 330 | arc['arc_hash_break']['collisions']) |
ea04106b | 331 | sys.stdout.write("\tChain Max:\t\t\t\t%s\n" % |
cae5b340 | 332 | arc['arc_hash_break']['chain_max']) |
ea04106b | 333 | sys.stdout.write("\tChains:\t\t\t\t\t%s\n" % |
cae5b340 | 334 | arc['arc_hash_break']['chains']) |
ea04106b AX |
335 | |
336 | ||
337 | def get_arc_efficiency(Kstat): | |
338 | output = {} | |
339 | ||
340 | arc_hits = Kstat["kstat.zfs.misc.arcstats.hits"] | |
341 | arc_misses = Kstat["kstat.zfs.misc.arcstats.misses"] | |
342 | demand_data_hits = Kstat["kstat.zfs.misc.arcstats.demand_data_hits"] | |
343 | demand_data_misses = Kstat["kstat.zfs.misc.arcstats.demand_data_misses"] | |
344 | demand_metadata_hits = Kstat[ | |
345 | "kstat.zfs.misc.arcstats.demand_metadata_hits" | |
346 | ] | |
347 | demand_metadata_misses = Kstat[ | |
348 | "kstat.zfs.misc.arcstats.demand_metadata_misses" | |
349 | ] | |
350 | mfu_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mfu_ghost_hits"] | |
351 | mfu_hits = Kstat["kstat.zfs.misc.arcstats.mfu_hits"] | |
352 | mru_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mru_ghost_hits"] | |
353 | mru_hits = Kstat["kstat.zfs.misc.arcstats.mru_hits"] | |
354 | prefetch_data_hits = Kstat["kstat.zfs.misc.arcstats.prefetch_data_hits"] | |
355 | prefetch_data_misses = Kstat[ | |
356 | "kstat.zfs.misc.arcstats.prefetch_data_misses" | |
357 | ] | |
358 | prefetch_metadata_hits = Kstat[ | |
359 | "kstat.zfs.misc.arcstats.prefetch_metadata_hits" | |
360 | ] | |
361 | prefetch_metadata_misses = Kstat[ | |
362 | "kstat.zfs.misc.arcstats.prefetch_metadata_misses" | |
363 | ] | |
364 | ||
365 | anon_hits = arc_hits - ( | |
366 | mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits | |
367 | ) | |
368 | arc_accesses_total = (arc_hits + arc_misses) | |
369 | demand_data_total = (demand_data_hits + demand_data_misses) | |
370 | prefetch_data_total = (prefetch_data_hits + prefetch_data_misses) | |
371 | real_hits = (mfu_hits + mru_hits) | |
372 | ||
373 | output["total_accesses"] = fHits(arc_accesses_total) | |
374 | output["cache_hit_ratio"] = { | |
375 | 'per': fPerc(arc_hits, arc_accesses_total), | |
376 | 'num': fHits(arc_hits), | |
377 | } | |
378 | output["cache_miss_ratio"] = { | |
379 | 'per': fPerc(arc_misses, arc_accesses_total), | |
380 | 'num': fHits(arc_misses), | |
381 | } | |
382 | output["actual_hit_ratio"] = { | |
383 | 'per': fPerc(real_hits, arc_accesses_total), | |
384 | 'num': fHits(real_hits), | |
385 | } | |
386 | output["data_demand_efficiency"] = { | |
387 | 'per': fPerc(demand_data_hits, demand_data_total), | |
388 | 'num': fHits(demand_data_total), | |
389 | } | |
390 | ||
391 | if prefetch_data_total > 0: | |
392 | output["data_prefetch_efficiency"] = { | |
393 | 'per': fPerc(prefetch_data_hits, prefetch_data_total), | |
394 | 'num': fHits(prefetch_data_total), | |
395 | } | |
396 | ||
397 | if anon_hits > 0: | |
398 | output["cache_hits_by_cache_list"] = {} | |
399 | output["cache_hits_by_cache_list"]["anonymously_used"] = { | |
400 | 'per': fPerc(anon_hits, arc_hits), | |
401 | 'num': fHits(anon_hits), | |
402 | } | |
403 | ||
404 | output["most_recently_used"] = { | |
405 | 'per': fPerc(mru_hits, arc_hits), | |
406 | 'num': fHits(mru_hits), | |
407 | } | |
408 | output["most_frequently_used"] = { | |
409 | 'per': fPerc(mfu_hits, arc_hits), | |
410 | 'num': fHits(mfu_hits), | |
411 | } | |
412 | output["most_recently_used_ghost"] = { | |
413 | 'per': fPerc(mru_ghost_hits, arc_hits), | |
414 | 'num': fHits(mru_ghost_hits), | |
415 | } | |
416 | output["most_frequently_used_ghost"] = { | |
417 | 'per': fPerc(mfu_ghost_hits, arc_hits), | |
418 | 'num': fHits(mfu_ghost_hits), | |
419 | } | |
420 | ||
421 | output["cache_hits_by_data_type"] = {} | |
422 | output["cache_hits_by_data_type"]["demand_data"] = { | |
423 | 'per': fPerc(demand_data_hits, arc_hits), | |
424 | 'num': fHits(demand_data_hits), | |
425 | } | |
426 | output["cache_hits_by_data_type"]["prefetch_data"] = { | |
427 | 'per': fPerc(prefetch_data_hits, arc_hits), | |
428 | 'num': fHits(prefetch_data_hits), | |
429 | } | |
430 | output["cache_hits_by_data_type"]["demand_metadata"] = { | |
431 | 'per': fPerc(demand_metadata_hits, arc_hits), | |
432 | 'num': fHits(demand_metadata_hits), | |
433 | } | |
434 | output["cache_hits_by_data_type"]["prefetch_metadata"] = { | |
435 | 'per': fPerc(prefetch_metadata_hits, arc_hits), | |
436 | 'num': fHits(prefetch_metadata_hits), | |
437 | } | |
438 | ||
439 | output["cache_misses_by_data_type"] = {} | |
440 | output["cache_misses_by_data_type"]["demand_data"] = { | |
441 | 'per': fPerc(demand_data_misses, arc_misses), | |
442 | 'num': fHits(demand_data_misses), | |
443 | } | |
444 | output["cache_misses_by_data_type"]["prefetch_data"] = { | |
445 | 'per': fPerc(prefetch_data_misses, arc_misses), | |
446 | 'num': fHits(prefetch_data_misses), | |
447 | } | |
448 | output["cache_misses_by_data_type"]["demand_metadata"] = { | |
449 | 'per': fPerc(demand_metadata_misses, arc_misses), | |
450 | 'num': fHits(demand_metadata_misses), | |
451 | } | |
452 | output["cache_misses_by_data_type"]["prefetch_metadata"] = { | |
453 | 'per': fPerc(prefetch_metadata_misses, arc_misses), | |
454 | 'num': fHits(prefetch_metadata_misses), | |
455 | } | |
456 | ||
457 | return output | |
458 | ||
459 | ||
460 | def _arc_efficiency(Kstat): | |
461 | arc = get_arc_efficiency(Kstat) | |
462 | ||
463 | sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" % | |
cae5b340 | 464 | arc['total_accesses']) |
ea04106b AX |
465 | sys.stdout.write("\tCache Hit Ratio:\t\t%s\t%s\n" % ( |
466 | arc['cache_hit_ratio']['per'], | |
467 | arc['cache_hit_ratio']['num'], | |
468 | ) | |
469 | ) | |
470 | sys.stdout.write("\tCache Miss Ratio:\t\t%s\t%s\n" % ( | |
471 | arc['cache_miss_ratio']['per'], | |
472 | arc['cache_miss_ratio']['num'], | |
473 | ) | |
474 | ) | |
475 | ||
476 | sys.stdout.write("\tActual Hit Ratio:\t\t%s\t%s\n" % ( | |
477 | arc['actual_hit_ratio']['per'], | |
478 | arc['actual_hit_ratio']['num'], | |
479 | ) | |
480 | ) | |
481 | ||
482 | sys.stdout.write("\n") | |
483 | sys.stdout.write("\tData Demand Efficiency:\t\t%s\t%s\n" % ( | |
484 | arc['data_demand_efficiency']['per'], | |
485 | arc['data_demand_efficiency']['num'], | |
486 | ) | |
487 | ) | |
488 | ||
489 | if 'data_prefetch_efficiency' in arc: | |
490 | sys.stdout.write("\tData Prefetch Efficiency:\t%s\t%s\n" % ( | |
491 | arc['data_prefetch_efficiency']['per'], | |
492 | arc['data_prefetch_efficiency']['num'], | |
493 | ) | |
494 | ) | |
495 | sys.stdout.write("\n") | |
496 | ||
497 | sys.stdout.write("\tCACHE HITS BY CACHE LIST:\n") | |
498 | if 'cache_hits_by_cache_list' in arc: | |
499 | sys.stdout.write("\t Anonymously Used:\t\t%s\t%s\n" % ( | |
500 | arc['cache_hits_by_cache_list']['anonymously_used']['per'], | |
501 | arc['cache_hits_by_cache_list']['anonymously_used']['num'], | |
502 | ) | |
503 | ) | |
504 | sys.stdout.write("\t Most Recently Used:\t\t%s\t%s\n" % ( | |
505 | arc['most_recently_used']['per'], | |
506 | arc['most_recently_used']['num'], | |
507 | ) | |
508 | ) | |
509 | sys.stdout.write("\t Most Frequently Used:\t\t%s\t%s\n" % ( | |
510 | arc['most_frequently_used']['per'], | |
511 | arc['most_frequently_used']['num'], | |
512 | ) | |
513 | ) | |
514 | sys.stdout.write("\t Most Recently Used Ghost:\t%s\t%s\n" % ( | |
515 | arc['most_recently_used_ghost']['per'], | |
516 | arc['most_recently_used_ghost']['num'], | |
517 | ) | |
518 | ) | |
519 | sys.stdout.write("\t Most Frequently Used Ghost:\t%s\t%s\n" % ( | |
520 | arc['most_frequently_used_ghost']['per'], | |
521 | arc['most_frequently_used_ghost']['num'], | |
522 | ) | |
523 | ) | |
524 | ||
525 | sys.stdout.write("\n\tCACHE HITS BY DATA TYPE:\n") | |
526 | sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % ( | |
527 | arc["cache_hits_by_data_type"]['demand_data']['per'], | |
528 | arc["cache_hits_by_data_type"]['demand_data']['num'], | |
529 | ) | |
530 | ) | |
531 | sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % ( | |
532 | arc["cache_hits_by_data_type"]['prefetch_data']['per'], | |
533 | arc["cache_hits_by_data_type"]['prefetch_data']['num'], | |
534 | ) | |
535 | ) | |
536 | sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % ( | |
537 | arc["cache_hits_by_data_type"]['demand_metadata']['per'], | |
538 | arc["cache_hits_by_data_type"]['demand_metadata']['num'], | |
539 | ) | |
540 | ) | |
541 | sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % ( | |
542 | arc["cache_hits_by_data_type"]['prefetch_metadata']['per'], | |
543 | arc["cache_hits_by_data_type"]['prefetch_metadata']['num'], | |
544 | ) | |
545 | ) | |
546 | ||
547 | sys.stdout.write("\n\tCACHE MISSES BY DATA TYPE:\n") | |
548 | sys.stdout.write("\t Demand Data:\t\t\t%s\t%s\n" % ( | |
549 | arc["cache_misses_by_data_type"]['demand_data']['per'], | |
550 | arc["cache_misses_by_data_type"]['demand_data']['num'], | |
551 | ) | |
552 | ) | |
553 | sys.stdout.write("\t Prefetch Data:\t\t%s\t%s\n" % ( | |
554 | arc["cache_misses_by_data_type"]['prefetch_data']['per'], | |
555 | arc["cache_misses_by_data_type"]['prefetch_data']['num'], | |
556 | ) | |
557 | ) | |
558 | sys.stdout.write("\t Demand Metadata:\t\t%s\t%s\n" % ( | |
559 | arc["cache_misses_by_data_type"]['demand_metadata']['per'], | |
560 | arc["cache_misses_by_data_type"]['demand_metadata']['num'], | |
561 | ) | |
562 | ) | |
563 | sys.stdout.write("\t Prefetch Metadata:\t\t%s\t%s\n" % ( | |
564 | arc["cache_misses_by_data_type"]['prefetch_metadata']['per'], | |
565 | arc["cache_misses_by_data_type"]['prefetch_metadata']['num'], | |
566 | ) | |
567 | ) | |
568 | ||
569 | ||
570 | def get_l2arc_summary(Kstat): | |
571 | output = {} | |
572 | ||
573 | l2_abort_lowmem = Kstat["kstat.zfs.misc.arcstats.l2_abort_lowmem"] | |
574 | l2_cksum_bad = Kstat["kstat.zfs.misc.arcstats.l2_cksum_bad"] | |
575 | l2_evict_lock_retry = Kstat["kstat.zfs.misc.arcstats.l2_evict_lock_retry"] | |
576 | l2_evict_reading = Kstat["kstat.zfs.misc.arcstats.l2_evict_reading"] | |
577 | l2_feeds = Kstat["kstat.zfs.misc.arcstats.l2_feeds"] | |
578 | l2_free_on_write = Kstat["kstat.zfs.misc.arcstats.l2_free_on_write"] | |
579 | l2_hdr_size = Kstat["kstat.zfs.misc.arcstats.l2_hdr_size"] | |
580 | l2_hits = Kstat["kstat.zfs.misc.arcstats.l2_hits"] | |
581 | l2_io_error = Kstat["kstat.zfs.misc.arcstats.l2_io_error"] | |
582 | l2_misses = Kstat["kstat.zfs.misc.arcstats.l2_misses"] | |
583 | l2_rw_clash = Kstat["kstat.zfs.misc.arcstats.l2_rw_clash"] | |
584 | l2_size = Kstat["kstat.zfs.misc.arcstats.l2_size"] | |
585 | l2_asize = Kstat["kstat.zfs.misc.arcstats.l2_asize"] | |
586 | l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"] | |
587 | l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"] | |
588 | l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"] | |
589 | ||
590 | l2_access_total = (l2_hits + l2_misses) | |
591 | output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error) | |
592 | ||
593 | output['l2_access_total'] = l2_access_total | |
594 | output['l2_size'] = l2_size | |
595 | output['l2_asize'] = l2_asize | |
596 | ||
597 | if l2_size > 0 and l2_access_total > 0: | |
598 | ||
599 | if output['l2_health_count'] > 0: | |
600 | output["health"] = "DEGRADED" | |
601 | else: | |
602 | output["health"] = "HEALTHY" | |
603 | ||
604 | output["low_memory_aborts"] = fHits(l2_abort_lowmem) | |
605 | output["free_on_write"] = fHits(l2_free_on_write) | |
606 | output["rw_clashes"] = fHits(l2_rw_clash) | |
607 | output["bad_checksums"] = fHits(l2_cksum_bad) | |
608 | output["io_errors"] = fHits(l2_io_error) | |
609 | ||
610 | output["l2_arc_size"] = {} | |
611 | output["l2_arc_size"]["adative"] = fBytes(l2_size) | |
612 | output["l2_arc_size"]["actual"] = { | |
613 | 'per': fPerc(l2_asize, l2_size), | |
614 | 'num': fBytes(l2_asize) | |
615 | } | |
616 | output["l2_arc_size"]["head_size"] = { | |
617 | 'per': fPerc(l2_hdr_size, l2_size), | |
618 | 'num': fBytes(l2_hdr_size), | |
619 | } | |
620 | ||
621 | output["l2_arc_evicts"] = {} | |
622 | output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry) | |
623 | output["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading) | |
624 | ||
625 | output['l2_arc_breakdown'] = {} | |
626 | output['l2_arc_breakdown']['value'] = fHits(l2_access_total) | |
627 | output['l2_arc_breakdown']['hit_ratio'] = { | |
628 | 'per': fPerc(l2_hits, l2_access_total), | |
629 | 'num': fHits(l2_hits), | |
630 | } | |
631 | output['l2_arc_breakdown']['miss_ratio'] = { | |
632 | 'per': fPerc(l2_misses, l2_access_total), | |
633 | 'num': fHits(l2_misses), | |
634 | } | |
635 | output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds) | |
636 | ||
637 | output['l2_arc_buffer'] = {} | |
638 | ||
639 | output['l2_arc_writes'] = {} | |
640 | output['l2_writes_done'] = l2_writes_done | |
641 | output['l2_writes_sent'] = l2_writes_sent | |
642 | if l2_writes_done != l2_writes_sent: | |
643 | output['l2_arc_writes']['writes_sent'] = { | |
644 | 'value': "FAULTED", | |
645 | 'num': fHits(l2_writes_sent), | |
646 | } | |
647 | output['l2_arc_writes']['done_ratio'] = { | |
648 | 'per': fPerc(l2_writes_done, l2_writes_sent), | |
649 | 'num': fHits(l2_writes_done), | |
650 | } | |
651 | output['l2_arc_writes']['error_ratio'] = { | |
652 | 'per': fPerc(l2_writes_error, l2_writes_sent), | |
653 | 'num': fHits(l2_writes_error), | |
654 | } | |
655 | else: | |
656 | output['l2_arc_writes']['writes_sent'] = { | |
657 | 'per': fPerc(100), | |
658 | 'num': fHits(l2_writes_sent), | |
659 | } | |
660 | ||
661 | return output | |
662 | ||
663 | ||
664 | def _l2arc_summary(Kstat): | |
665 | ||
666 | arc = get_l2arc_summary(Kstat) | |
667 | ||
668 | if arc['l2_size'] > 0 and arc['l2_access_total'] > 0: | |
669 | sys.stdout.write("L2 ARC Summary: ") | |
670 | if arc['l2_health_count'] > 0: | |
671 | sys.stdout.write("(DEGRADED)\n") | |
672 | else: | |
673 | sys.stdout.write("(HEALTHY)\n") | |
674 | sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" % | |
cae5b340 | 675 | arc['low_memory_aborts']) |
ea04106b AX |
676 | sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write']) |
677 | sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes']) | |
678 | sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums']) | |
679 | sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors']) | |
680 | sys.stdout.write("\n") | |
681 | ||
682 | sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" % | |
cae5b340 | 683 | arc["l2_arc_size"]["adative"]) |
ea04106b AX |
684 | sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % ( |
685 | arc["l2_arc_size"]["actual"]["per"], | |
686 | arc["l2_arc_size"]["actual"]["num"], | |
687 | ) | |
688 | ) | |
689 | sys.stdout.write("\tHeader Size:\t\t\t%s\t%s\n" % ( | |
690 | arc["l2_arc_size"]["head_size"]["per"], | |
691 | arc["l2_arc_size"]["head_size"]["num"], | |
692 | ) | |
693 | ) | |
694 | sys.stdout.write("\n") | |
695 | ||
cae5b340 AX |
696 | if arc["l2_arc_evicts"]['lock_retries'] != '0' or \ |
697 | arc["l2_arc_evicts"]["reading"] != '0': | |
ea04106b AX |
698 | sys.stdout.write("L2 ARC Evicts:\n") |
699 | sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" % | |
cae5b340 | 700 | arc["l2_arc_evicts"]['lock_retries']) |
ea04106b | 701 | sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" % |
cae5b340 | 702 | arc["l2_arc_evicts"]["reading"]) |
ea04106b AX |
703 | sys.stdout.write("\n") |
704 | ||
705 | sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" % | |
cae5b340 | 706 | arc['l2_arc_breakdown']['value']) |
ea04106b AX |
707 | sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( |
708 | arc['l2_arc_breakdown']['hit_ratio']['per'], | |
709 | arc['l2_arc_breakdown']['hit_ratio']['num'], | |
710 | ) | |
711 | ) | |
712 | ||
713 | sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( | |
714 | arc['l2_arc_breakdown']['miss_ratio']['per'], | |
715 | arc['l2_arc_breakdown']['miss_ratio']['num'], | |
716 | ) | |
717 | ) | |
718 | ||
719 | sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" % | |
cae5b340 | 720 | arc['l2_arc_breakdown']['feeds']) |
ea04106b AX |
721 | sys.stdout.write("\n") |
722 | ||
723 | sys.stdout.write("L2 ARC Writes:\n") | |
724 | if arc['l2_writes_done'] != arc['l2_writes_sent']: | |
725 | sys.stdout.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % ( | |
726 | arc['l2_arc_writes']['writes_sent']['value'], | |
727 | arc['l2_arc_writes']['writes_sent']['num'], | |
728 | ) | |
729 | ) | |
730 | sys.stdout.write("\t Done Ratio:\t\t\t%s\t%s\n" % ( | |
731 | arc['l2_arc_writes']['done_ratio']['per'], | |
732 | arc['l2_arc_writes']['done_ratio']['num'], | |
733 | ) | |
734 | ) | |
735 | sys.stdout.write("\t Error Ratio:\t\t\t%s\t%s\n" % ( | |
736 | arc['l2_arc_writes']['error_ratio']['per'], | |
737 | arc['l2_arc_writes']['error_ratio']['num'], | |
738 | ) | |
739 | ) | |
740 | else: | |
741 | sys.stdout.write("\tWrites Sent:\t\t\t%s\t%s\n" % ( | |
742 | arc['l2_arc_writes']['writes_sent']['per'], | |
743 | arc['l2_arc_writes']['writes_sent']['num'], | |
744 | ) | |
745 | ) | |
746 | ||
747 | ||
748 | def get_dmu_summary(Kstat): | |
749 | output = {} | |
750 | ||
ea04106b AX |
751 | zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"] |
752 | zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"] | |
ea04106b AX |
753 | |
754 | zfetch_access_total = (zfetch_hits + zfetch_misses) | |
ea04106b AX |
755 | output['zfetch_access_total'] = zfetch_access_total |
756 | ||
757 | if zfetch_access_total > 0: | |
ea04106b AX |
758 | output['dmu'] = {} |
759 | output['dmu']['efficiency'] = {} | |
760 | output['dmu']['efficiency']['value'] = fHits(zfetch_access_total) | |
761 | output['dmu']['efficiency']['hit_ratio'] = { | |
762 | 'per': fPerc(zfetch_hits, zfetch_access_total), | |
763 | 'num': fHits(zfetch_hits), | |
764 | } | |
765 | output['dmu']['efficiency']['miss_ratio'] = { | |
766 | 'per': fPerc(zfetch_misses, zfetch_access_total), | |
767 | 'num': fHits(zfetch_misses), | |
768 | } | |
769 | ||
ea04106b AX |
770 | return output |
771 | ||
772 | ||
773 | def _dmu_summary(Kstat): | |
774 | ||
775 | arc = get_dmu_summary(Kstat) | |
776 | ||
777 | if arc['zfetch_access_total'] > 0: | |
cae5b340 AX |
778 | sys.stdout.write("DMU Prefetch Efficiency:\t\t\t\t\t%s\n" % |
779 | arc['dmu']['efficiency']['value']) | |
ea04106b AX |
780 | sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( |
781 | arc['dmu']['efficiency']['hit_ratio']['per'], | |
782 | arc['dmu']['efficiency']['hit_ratio']['num'], | |
783 | ) | |
784 | ) | |
785 | sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( | |
786 | arc['dmu']['efficiency']['miss_ratio']['per'], | |
787 | arc['dmu']['efficiency']['miss_ratio']['num'], | |
788 | ) | |
789 | ) | |
790 | ||
791 | sys.stdout.write("\n") | |
792 | ||
ea04106b AX |
793 | |
794 | def get_vdev_summary(Kstat): | |
795 | output = {} | |
796 | ||
797 | vdev_cache_delegations = \ | |
cae5b340 | 798 | Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"] |
ea04106b AX |
799 | vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"] |
800 | vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"] | |
801 | vdev_cache_total = (vdev_cache_misses + vdev_cache_hits + | |
cae5b340 | 802 | vdev_cache_delegations) |
ea04106b AX |
803 | |
804 | output['vdev_cache_total'] = vdev_cache_total | |
805 | ||
806 | if vdev_cache_total > 0: | |
807 | output['summary'] = fHits(vdev_cache_total) | |
808 | output['hit_ratio'] = { | |
809 | 'per': fPerc(vdev_cache_hits, vdev_cache_total), | |
810 | 'num': fHits(vdev_cache_hits), | |
811 | } | |
812 | output['miss_ratio'] = { | |
813 | 'per': fPerc(vdev_cache_misses, vdev_cache_total), | |
814 | 'num': fHits(vdev_cache_misses), | |
815 | } | |
816 | output['delegations'] = { | |
817 | 'per': fPerc(vdev_cache_delegations, vdev_cache_total), | |
818 | 'num': fHits(vdev_cache_delegations), | |
819 | } | |
820 | ||
821 | return output | |
822 | ||
823 | ||
824 | def _vdev_summary(Kstat): | |
825 | arc = get_vdev_summary(Kstat) | |
826 | ||
827 | if arc['vdev_cache_total'] > 0: | |
828 | sys.stdout.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc['summary']) | |
829 | sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % ( | |
830 | arc['hit_ratio']['per'], | |
831 | arc['hit_ratio']['num'], | |
832 | )) | |
833 | sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % ( | |
834 | arc['miss_ratio']['per'], | |
835 | arc['miss_ratio']['num'], | |
836 | )) | |
837 | sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % ( | |
838 | arc['delegations']['per'], | |
839 | arc['delegations']['num'], | |
840 | )) | |
841 | ||
842 | ||
843 | def _tunable_summary(Kstat): | |
844 | global show_tunable_descriptions | |
845 | global alternate_tunable_layout | |
846 | ||
847 | names = listdir("/sys/module/zfs/parameters/") | |
848 | ||
849 | values = {} | |
850 | for name in names: | |
cae5b340 AX |
851 | with open("/sys/module/zfs/parameters/" + name) as f: |
852 | value = f.read() | |
ea04106b AX |
853 | values[name] = value.strip() |
854 | ||
855 | descriptions = {} | |
856 | ||
857 | if show_tunable_descriptions: | |
858 | try: | |
859 | command = ["/sbin/modinfo", "zfs", "-0"] | |
860 | p = Popen(command, stdin=PIPE, stdout=PIPE, | |
cae5b340 | 861 | stderr=PIPE, shell=False, close_fds=True) |
ea04106b AX |
862 | p.wait() |
863 | ||
864 | description_list = p.communicate()[0].strip().split('\0') | |
865 | ||
866 | if p.returncode == 0: | |
867 | for tunable in description_list: | |
868 | if tunable[0:5] == 'parm:': | |
869 | tunable = tunable[5:].strip() | |
870 | name, description = tunable.split(':', 1) | |
871 | if not description: | |
872 | description = "Description unavailable" | |
873 | descriptions[name] = description | |
874 | else: | |
875 | sys.stderr.write("%s: '%s' exited with code %i\n" % | |
cae5b340 | 876 | (sys.argv[0], command[0], p.returncode)) |
ea04106b AX |
877 | sys.stderr.write("Tunable descriptions will be disabled.\n") |
878 | except OSError as e: | |
879 | sys.stderr.write("%s: Cannot run '%s': %s\n" % | |
cae5b340 | 880 | (sys.argv[0], command[0], e.strerror)) |
ea04106b AX |
881 | sys.stderr.write("Tunable descriptions will be disabled.\n") |
882 | ||
883 | sys.stdout.write("ZFS Tunable:\n") | |
884 | for name in names: | |
885 | if not name: | |
886 | continue | |
887 | ||
888 | format = "\t%-50s%s\n" | |
889 | if alternate_tunable_layout: | |
890 | format = "\t%s=%s\n" | |
891 | ||
4d815aed | 892 | if show_tunable_descriptions and name in descriptions: |
ea04106b AX |
893 | sys.stdout.write("\t# %s\n" % descriptions[name]) |
894 | ||
895 | sys.stdout.write(format % (name, values[name])) | |
896 | ||
897 | ||
898 | unSub = [ | |
899 | _arc_summary, | |
900 | _arc_efficiency, | |
901 | _l2arc_summary, | |
902 | _dmu_summary, | |
903 | _vdev_summary, | |
904 | _tunable_summary | |
905 | ] | |
906 | ||
907 | ||
908 | def zfs_header(): | |
909 | daydate = time.strftime("%a %b %d %H:%M:%S %Y") | |
910 | ||
911 | div1() | |
912 | sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate) | |
913 | div2() | |
914 | ||
915 | ||
916 | def usage(): | |
917 | sys.stdout.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n") | |
918 | sys.stdout.write("\t -h, --help : " | |
cae5b340 | 919 | "Print this help message and exit\n") |
ea04106b | 920 | sys.stdout.write("\t -a, --alternate : " |
cae5b340 | 921 | "Show an alternate sysctl layout\n") |
ea04106b | 922 | sys.stdout.write("\t -d, --description : " |
cae5b340 | 923 | "Show the sysctl descriptions\n") |
ea04106b | 924 | sys.stdout.write("\t -p PAGE, --page=PAGE : " |
cae5b340 | 925 | "Select a single output page to display,\n") |
ea04106b | 926 | sys.stdout.write("\t " |
cae5b340 AX |
927 | "should be an integer between 1 and " + |
928 | str(len(unSub)) + "\n\n") | |
ea04106b AX |
929 | sys.stdout.write("Examples:\n") |
930 | sys.stdout.write("\tarc_summary.py -a\n") | |
931 | sys.stdout.write("\tarc_summary.py -p 4\n") | |
932 | sys.stdout.write("\tarc_summary.py -ad\n") | |
933 | sys.stdout.write("\tarc_summary.py --page=2\n") | |
934 | ||
cae5b340 | 935 | |
ea04106b AX |
936 | def main(): |
937 | global show_tunable_descriptions | |
938 | global alternate_tunable_layout | |
939 | ||
940 | opts, args = getopt.getopt( | |
941 | sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"] | |
942 | ) | |
943 | ||
944 | args = {} | |
945 | for opt, arg in opts: | |
946 | if opt in ('-a', '--alternate'): | |
947 | args['a'] = True | |
948 | if opt in ('-d', '--description'): | |
949 | args['d'] = True | |
950 | if opt in ('-p', '--page'): | |
951 | args['p'] = arg | |
952 | if opt in ('-h', '--help'): | |
953 | usage() | |
954 | sys.exit() | |
955 | ||
956 | Kstat = get_Kstat() | |
957 | ||
958 | alternate_tunable_layout = 'a' in args | |
959 | show_tunable_descriptions = 'd' in args | |
960 | ||
961 | pages = [] | |
962 | ||
963 | if 'p' in args: | |
964 | try: | |
965 | pages.append(unSub[int(args['p']) - 1]) | |
cae5b340 | 966 | except IndexError: |
ea04106b | 967 | sys.stderr.write('the argument to -p must be between 1 and ' + |
cae5b340 | 968 | str(len(unSub)) + '\n') |
ea04106b AX |
969 | sys.exit() |
970 | else: | |
971 | pages = unSub | |
972 | ||
973 | zfs_header() | |
974 | for page in pages: | |
975 | page(Kstat) | |
976 | div2() | |
977 | ||
cae5b340 | 978 | |
ea04106b AX |
979 | if __name__ == '__main__': |
980 | main() |