]>
git.proxmox.com Git - mirror_zfs-debian.git/blob - cmd/dbufstat/dbufstat.py
dda0a143f783ce2c95bbc3063ca2c943cfb1f093
3 # Print out statistics for all cached dmu buffers. This information
4 # is available through the dbufs kstat and may be post-processed as
5 # needed by the script.
9 # The contents of this file are subject to the terms of the
10 # Common Development and Distribution License, Version 1.0 only
11 # (the "License"). You may not use this file except in compliance
14 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
15 # or http://www.opensolaris.org/os/licensing.
16 # See the License for the specific language governing permissions
17 # and limitations under the License.
19 # When distributing Covered Code, include this CDDL HEADER in each
20 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
21 # If applicable, add the following below this CDDL HEADER, with the
22 # fields enclosed by brackets "[]" replaced with your own identifying
23 # information: Portions Copyright [yyyy] [name of copyright owner]
27 # Copyright (C) 2013 Lawrence Livermore National Security, LLC.
28 # Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
35 bhdr
= ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
36 bxhdr
= ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
37 "meta", "state", "dbholds", "list", "atype", "flags",
38 "count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
39 "l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
40 "data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
41 bincompat
= ["cached", "direct", "indirect", "bonus", "spill"]
43 dhdr
= ["pool", "objset", "object", "dtype", "cached"]
44 dxhdr
= ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
45 "bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
46 "indirect", "bonus", "spill"]
47 dincompat
= ["level", "blkid", "offset", "dbsize", "meta", "state", "dbholds",
48 "list", "atype", "flags", "count", "asize", "access",
49 "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr", "l2_asize",
52 thdr
= ["pool", "objset", "dtype", "cached"]
53 txhdr
= ["pool", "objset", "dtype", "cached", "direct", "indirect",
55 tincompat
= ["object", "level", "blkid", "offset", "dbsize", "meta", "state",
56 "dbholds", "list", "atype", "flags", "count", "asize",
57 "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
58 "l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
59 "bsize", "lvls", "dholds", "blocks", "dsize"]
62 # hdr: [size, scale, description]
63 "pool": [15, -1, "pool name"],
64 "objset": [6, -1, "dataset identification number"],
65 "object": [10, -1, "object number"],
66 "level": [5, -1, "indirection level of buffer"],
67 "blkid": [8, -1, "block number of buffer"],
68 "offset": [12, 1024, "offset in object of buffer"],
69 "dbsize": [7, 1024, "size of buffer"],
70 "meta": [4, -1, "is this buffer metadata?"],
71 "state": [5, -1, "state of buffer (read, cached, etc)"],
72 "dbholds": [7, 1000, "number of holds on buffer"],
73 "list": [4, -1, "which ARC list contains this buffer"],
74 "atype": [7, -1, "ARC header type (data or metadata)"],
75 "flags": [8, -1, "ARC read flags"],
76 "count": [5, -1, "ARC data count"],
77 "asize": [7, 1024, "size of this ARC buffer"],
78 "access": [10, -1, "time this ARC buffer was last accessed"],
79 "mru": [5, 1000, "hits while on the ARC's MRU list"],
80 "gmru": [5, 1000, "hits while on the ARC's MRU ghost list"],
81 "mfu": [5, 1000, "hits while on the ARC's MFU list"],
82 "gmfu": [5, 1000, "hits while on the ARC's MFU ghost list"],
83 "l2": [5, 1000, "hits while on the L2ARC"],
84 "l2_dattr": [8, -1, "L2ARC disk address/offset"],
85 "l2_asize": [8, 1024, "L2ARC alloc'd size (depending on compression)"],
86 "l2_comp": [21, -1, "L2ARC compression algorithm for buffer"],
87 "aholds": [6, 1000, "number of holds on this ARC buffer"],
88 "dtype": [27, -1, "dnode type"],
89 "btype": [27, -1, "bonus buffer type"],
90 "data_bs": [7, 1024, "data block size"],
91 "meta_bs": [7, 1024, "metadata block size"],
92 "bsize": [6, 1024, "bonus buffer size"],
93 "lvls": [6, -1, "number of indirection levels"],
94 "dholds": [6, 1000, "number of holds on dnode"],
95 "blocks": [8, 1000, "number of allocated blocks"],
96 "dsize": [12, 1024, "size of dnode"],
97 "cached": [6, 1024, "bytes cached for all blocks"],
98 "direct": [6, 1024, "bytes cached for direct blocks"],
99 "indirect": [8, 1024, "bytes cached for indirect blocks"],
100 "bonus": [5, 1024, "bytes cached for bonus buffer"],
101 "spill": [5, 1024, "bytes cached for spill block"],
106 sep
= " " # Default separator is 2 spaces
107 cmd
= ("Usage: dbufstat.py [-bdhrtvx] [-i file] [-f fields] [-o file] "
112 def print_incompat_helper(incompat
):
114 for key
in sorted(incompat
):
116 sys
.stderr
.write("\t")
118 sys
.stderr
.write(",\n\t")
121 sys
.stderr
.write(", ")
123 sys
.stderr
.write("%s" % key
)
126 sys
.stderr
.write("\n\n")
129 def detailed_usage():
130 sys
.stderr
.write("%s\n" % cmd
)
132 sys
.stderr
.write("Field definitions incompatible with '-b' option:\n")
133 print_incompat_helper(bincompat
)
135 sys
.stderr
.write("Field definitions incompatible with '-d' option:\n")
136 print_incompat_helper(dincompat
)
138 sys
.stderr
.write("Field definitions incompatible with '-t' option:\n")
139 print_incompat_helper(tincompat
)
141 sys
.stderr
.write("Field definitions are as follows:\n")
142 for key
in sorted(cols
.keys()):
143 sys
.stderr
.write("%11s : %s\n" % (key
, cols
[key
][2]))
144 sys
.stderr
.write("\n")
150 sys
.stderr
.write("%s\n" % cmd
)
151 sys
.stderr
.write("\t -b : Print table of information for each dbuf\n")
152 sys
.stderr
.write("\t -d : Print table of information for each dnode\n")
153 sys
.stderr
.write("\t -h : Print this help message\n")
154 sys
.stderr
.write("\t -r : Print raw values\n")
155 sys
.stderr
.write("\t -t : Print table of information for each dnode type"
157 sys
.stderr
.write("\t -v : List all possible field headers and definitions"
159 sys
.stderr
.write("\t -x : Print extended stats\n")
160 sys
.stderr
.write("\t -i : Redirect input from the specified file\n")
161 sys
.stderr
.write("\t -f : Specify specific fields to print (see -v)\n")
162 sys
.stderr
.write("\t -o : Redirect output to the specified file\n")
163 sys
.stderr
.write("\t -s : Override default field separator with custom "
164 "character or string\n")
165 sys
.stderr
.write("\nExamples:\n")
166 sys
.stderr
.write("\tdbufstat.py -d -o /tmp/d.log\n")
167 sys
.stderr
.write("\tdbufstat.py -t -s \",\" -o /tmp/t.log\n")
168 sys
.stderr
.write("\tdbufstat.py -v\n")
169 sys
.stderr
.write("\tdbufstat.py -d -f pool,object,objset,dsize,cached\n")
170 sys
.stderr
.write("\n")
175 def prettynum(sz
, scale
, num
=0):
178 suffix
= [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
182 if raw
or scale
== -1:
183 return "%*s" % (sz
, num
)
185 # Rounding error, return 0
189 while num
> scale
and index
< 5:
195 return "%*d" % (sz
, num
)
197 if (save
/ scale
) < 10:
198 return "%*.1f%s" % (sz
- 1, num
, suffix
[index
])
200 return "%*d%s" % (sz
- 1, num
, suffix
[index
])
209 sys
.stdout
.write("%s%s" % (
210 prettynum(cols
[col
][0], cols
[col
][1], v
[col
]), sep
))
211 sys
.stdout
.write("\n")
213 if e
.errno
== errno
.EPIPE
:
223 sys
.stdout
.write("%*s%s" % (cols
[col
][0], col
, sep
))
224 sys
.stdout
.write("\n")
226 if e
.errno
== errno
.EPIPE
:
230 def get_typestring(t
):
231 type_strings
= ["DMU_OT_NONE",
233 "DMU_OT_OBJECT_DIRECTORY",
234 "DMU_OT_OBJECT_ARRAY",
235 "DMU_OT_PACKED_NVLIST",
236 "DMU_OT_PACKED_NVLIST_SIZE",
240 "DMU_OT_SPACE_MAP_HEADER",
249 "DMU_OT_DSL_DIR_CHILD_MAP",
250 "DMU_OT_DSL_DS_SNAP_MAP",
252 "DMU_OT_DSL_DATASET",
256 "DMU_OT_PLAIN_FILE_CONTENTS",
257 "DMU_OT_DIRECTORY_CONTENTS",
258 "DMU_OT_MASTER_NODE",
259 "DMU_OT_UNLINKED_SET",
263 # other; for testing only!
264 "DMU_OT_PLAIN_OTHER",
265 "DMU_OT_UINT64_OTHER",
269 "DMU_OT_SPA_HISTORY",
270 "DMU_OT_SPA_HISTORY_OFFSETS",
277 "DMU_OT_NEXT_CLONES",
279 "DMU_OT_USERGROUP_USED",
280 "DMU_OT_USERGROUP_QUOTA",
285 "DMU_OT_SA_MASTER_NODE",
286 "DMU_OT_SA_ATTR_REGISTRATION",
287 "DMU_OT_SA_ATTR_LAYOUTS",
291 "DMU_OT_DEADLIST_HDR",
293 "DMU_OT_BPOBJ_SUBOBJ"]
295 # If "-rr" option is used, don't convert to string representation
300 return type_strings
[t
]
305 def get_compstring(c
):
306 comp_strings
= ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
307 "ZIO_COMPRESS_OFF", "ZIO_COMPRESS_LZJB",
308 "ZIO_COMPRESS_EMPTY", "ZIO_COMPRESS_GZIP_1",
309 "ZIO_COMPRESS_GZIP_2", "ZIO_COMPRESS_GZIP_3",
310 "ZIO_COMPRESS_GZIP_4", "ZIO_COMPRESS_GZIP_5",
311 "ZIO_COMPRESS_GZIP_6", "ZIO_COMPRESS_GZIP_7",
312 "ZIO_COMPRESS_GZIP_8", "ZIO_COMPRESS_GZIP_9",
313 "ZIO_COMPRESS_ZLE", "ZIO_COMPRESS_LZ4",
314 "ZIO_COMPRESS_FUNCTION"]
316 # If "-rr" option is used, don't convert to string representation
321 return comp_strings
[c
]
326 def parse_line(line
, labels
):
332 # These are "special" fields computed in the update_dict
333 # function, prevent KeyError exception on labels[col] for these.
334 if col
not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
335 val
= line
[labels
[col
]]
337 if col
in ['pool', 'flags']:
339 elif col
in ['dtype', 'btype']:
340 new
[col
] = get_typestring(int(val
))
341 elif col
in ['l2_comp']:
342 new
[col
] = get_compstring(int(val
))
349 def update_dict(d
, k
, line
, labels
):
350 pool
= line
[labels
['pool']]
351 objset
= line
[labels
['objset']]
352 key
= line
[labels
[k
]]
354 dbsize
= int(line
[labels
['dbsize']])
355 blkid
= int(line
[labels
['blkid']])
356 level
= int(line
[labels
['level']])
361 if objset
not in d
[pool
]:
362 d
[pool
][objset
] = dict()
364 if key
not in d
[pool
][objset
]:
365 d
[pool
][objset
][key
] = parse_line(line
, labels
)
366 d
[pool
][objset
][key
]['bonus'] = 0
367 d
[pool
][objset
][key
]['cached'] = 0
368 d
[pool
][objset
][key
]['direct'] = 0
369 d
[pool
][objset
][key
]['indirect'] = 0
370 d
[pool
][objset
][key
]['spill'] = 0
372 d
[pool
][objset
][key
]['cached'] += dbsize
375 d
[pool
][objset
][key
]['bonus'] += dbsize
377 d
[pool
][objset
][key
]['spill'] += dbsize
380 d
[pool
][objset
][key
]['direct'] += dbsize
382 d
[pool
][objset
][key
]['indirect'] += dbsize
389 for pool
in list(d
.keys()):
390 for objset
in list(d
[pool
].keys()):
391 for v
in list(d
[pool
][objset
].values()):
395 def dnodes_build_dict(filehandle
):
399 # First 3 lines are header information, skip the first two
403 # The third line contains the labels and index locations
404 for i
, v
in enumerate(next(filehandle
).split()):
407 # The rest of the file is buffer information
408 for line
in filehandle
:
409 update_dict(dnodes
, 'object', line
.split(), labels
)
414 def types_build_dict(filehandle
):
418 # First 3 lines are header information, skip the first two
422 # The third line contains the labels and index locations
423 for i
, v
in enumerate(next(filehandle
).split()):
426 # The rest of the file is buffer information
427 for line
in filehandle
:
428 update_dict(types
, 'dtype', line
.split(), labels
)
433 def buffers_print_all(filehandle
):
436 # First 3 lines are header information, skip the first two
440 # The third line contains the labels and index locations
441 for i
, v
in enumerate(next(filehandle
).split()):
446 # The rest of the file is buffer information
447 for line
in filehandle
:
448 print_values(parse_line(line
.split(), labels
))
467 opts
, args
= getopt
.getopt(
487 for opt
, arg
in opts
:
488 if opt
in ('-b', '--buffers'):
490 if opt
in ('-d', '--dnodes'):
492 if opt
in ('-f', '--columns'):
494 if opt
in ('-h', '--help'):
496 if opt
in ('-i', '--infile'):
498 if opt
in ('-o', '--outfile'):
500 if opt
in ('-r', '--raw'):
502 if opt
in ('-s', '--seperator'):
504 if opt
in ('-t', '--types'):
506 if opt
in ('-v', '--verbose'):
508 if opt
in ('-x', '--extended'):
511 if hflag
or (xflag
and desired_cols
):
517 # Ensure at most only one of b, d, or t flags are set
518 if (bflag
and dflag
) or (bflag
and tflag
) or (dflag
and tflag
):
522 hdr
= bxhdr
if xflag
else bhdr
524 hdr
= txhdr
if xflag
else thdr
525 else: # Even if dflag is False, it's the default if none set
527 hdr
= dxhdr
if xflag
else dhdr
530 hdr
= desired_cols
.split(",")
537 elif ((bflag
and bincompat
and ele
in bincompat
) or
538 (dflag
and dincompat
and ele
in dincompat
) or
539 (tflag
and tincompat
and ele
in tincompat
)):
543 sys
.stderr
.write("Invalid column definition! -- %s\n" % invalid
)
546 if len(incompat
) > 0:
547 sys
.stderr
.write("Incompatible field specified! -- %s\n" %
553 tmp
= open(ofile
, "w")
557 sys
.stderr
.write("Cannot open %s for writing\n" % ofile
)
561 ifile
= '/proc/spl/kstat/zfs/dbufs'
565 tmp
= open(ifile
, "r")
568 sys
.stderr
.write("Cannot open %s for reading\n" % ifile
)
572 buffers_print_all(sys
.stdin
)
575 print_dict(dnodes_build_dict(sys
.stdin
))
578 print_dict(types_build_dict(sys
.stdin
))
581 if __name__
== '__main__':