xref: /freebsd/sys/contrib/openzfs/cmd/dbufstat.in (revision a2b560cc)
1716fd348SMartin Matuska#!/usr/bin/env @PYTHON_SHEBANG@
2716fd348SMartin Matuska#
3716fd348SMartin Matuska# Print out statistics for all cached dmu buffers.  This information
4716fd348SMartin Matuska# is available through the dbufs kstat and may be post-processed as
5716fd348SMartin Matuska# needed by the script.
6716fd348SMartin Matuska#
7716fd348SMartin Matuska# CDDL HEADER START
8716fd348SMartin Matuska#
9716fd348SMartin Matuska# The contents of this file are subject to the terms of the
10716fd348SMartin Matuska# Common Development and Distribution License, Version 1.0 only
11716fd348SMartin Matuska# (the "License").  You may not use this file except in compliance
12716fd348SMartin Matuska# with the License.
13716fd348SMartin Matuska#
14716fd348SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
15271171e0SMartin Matuska# or https://opensource.org/licenses/CDDL-1.0.
16716fd348SMartin Matuska# See the License for the specific language governing permissions
17716fd348SMartin Matuska# and limitations under the License.
18716fd348SMartin Matuska#
19716fd348SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
20716fd348SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
21716fd348SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
22716fd348SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
23716fd348SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
24716fd348SMartin Matuska#
25716fd348SMartin Matuska# CDDL HEADER END
26716fd348SMartin Matuska#
27716fd348SMartin Matuska# Copyright (C) 2013 Lawrence Livermore National Security, LLC.
28716fd348SMartin Matuska# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
29716fd348SMartin Matuska#
30716fd348SMartin Matuska# This script must remain compatible with and Python 3.6+.
31716fd348SMartin Matuska#
32716fd348SMartin Matuska
33716fd348SMartin Matuskaimport sys
34716fd348SMartin Matuskaimport getopt
35716fd348SMartin Matuskaimport errno
36716fd348SMartin Matuskaimport re
37716fd348SMartin Matuska
38716fd348SMartin Matuskabhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
39716fd348SMartin Matuskabxhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
40*a2b560ccSMartin Matuska         "usize", "meta", "state", "dbholds", "dbc", "list", "atype", "flags",
41716fd348SMartin Matuska         "count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
42716fd348SMartin Matuska         "l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
43716fd348SMartin Matuska         "data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
44716fd348SMartin Matuskabincompat = ["cached", "direct", "indirect", "bonus", "spill"]
45716fd348SMartin Matuska
46716fd348SMartin Matuskadhdr = ["pool", "objset", "object", "dtype", "cached"]
47716fd348SMartin Matuskadxhdr = ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
48716fd348SMartin Matuska         "bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
49716fd348SMartin Matuska         "indirect", "bonus", "spill"]
50*a2b560ccSMartin Matuskadincompat = ["level", "blkid", "offset", "dbsize", "usize", "meta", "state",
51*a2b560ccSMartin Matuska             "dbholds", "dbc", "list", "atype", "flags", "count", "asize",
52*a2b560ccSMartin Matuska             "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
53*a2b560ccSMartin Matuska             "l2_asize", "l2_comp", "aholds"]
54716fd348SMartin Matuska
55716fd348SMartin Matuskathdr = ["pool", "objset", "dtype", "cached"]
56716fd348SMartin Matuskatxhdr = ["pool", "objset", "dtype", "cached", "direct", "indirect",
57716fd348SMartin Matuska         "bonus", "spill"]
58*a2b560ccSMartin Matuskatincompat = ["object", "level", "blkid", "offset", "dbsize", "usize", "meta",
59*a2b560ccSMartin Matuska             "state", "dbc", "dbholds", "list", "atype", "flags", "count",
60*a2b560ccSMartin Matuska             "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
61716fd348SMartin Matuska             "l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
62716fd348SMartin Matuska             "bsize", "lvls", "dholds", "blocks", "dsize"]
63716fd348SMartin Matuska
64716fd348SMartin Matuskacols = {
65716fd348SMartin Matuska    # hdr:        [size, scale, description]
66716fd348SMartin Matuska    "pool":       [15,   -1, "pool name"],
67716fd348SMartin Matuska    "objset":     [6,    -1, "dataset identification number"],
68716fd348SMartin Matuska    "object":     [10,   -1, "object number"],
69716fd348SMartin Matuska    "level":      [5,    -1, "indirection level of buffer"],
70716fd348SMartin Matuska    "blkid":      [8,    -1, "block number of buffer"],
71716fd348SMartin Matuska    "offset":     [12, 1024, "offset in object of buffer"],
72716fd348SMartin Matuska    "dbsize":     [7,  1024, "size of buffer"],
73*a2b560ccSMartin Matuska    "usize":      [7,  1024, "size of attached user data"],
74716fd348SMartin Matuska    "meta":       [4,    -1, "is this buffer metadata?"],
75716fd348SMartin Matuska    "state":      [5,    -1, "state of buffer (read, cached, etc)"],
76716fd348SMartin Matuska    "dbholds":    [7,  1000, "number of holds on buffer"],
77716fd348SMartin Matuska    "dbc":        [3,    -1, "in dbuf cache"],
78716fd348SMartin Matuska    "list":       [4,    -1, "which ARC list contains this buffer"],
79716fd348SMartin Matuska    "atype":      [7,    -1, "ARC header type (data or metadata)"],
80716fd348SMartin Matuska    "flags":      [9,    -1, "ARC read flags"],
81716fd348SMartin Matuska    "count":      [5,    -1, "ARC data count"],
82716fd348SMartin Matuska    "asize":      [7,  1024, "size of this ARC buffer"],
83716fd348SMartin Matuska    "access":     [10,   -1, "time this ARC buffer was last accessed"],
84716fd348SMartin Matuska    "mru":        [5,  1000, "hits while on the ARC's MRU list"],
85716fd348SMartin Matuska    "gmru":       [5,  1000, "hits while on the ARC's MRU ghost list"],
86716fd348SMartin Matuska    "mfu":        [5,  1000, "hits while on the ARC's MFU list"],
87716fd348SMartin Matuska    "gmfu":       [5,  1000, "hits while on the ARC's MFU ghost list"],
88716fd348SMartin Matuska    "l2":         [5,  1000, "hits while on the L2ARC"],
89716fd348SMartin Matuska    "l2_dattr":   [8,    -1, "L2ARC disk address/offset"],
90716fd348SMartin Matuska    "l2_asize":   [8,  1024, "L2ARC alloc'd size (depending on compression)"],
91716fd348SMartin Matuska    "l2_comp":    [21,   -1, "L2ARC compression algorithm for buffer"],
92716fd348SMartin Matuska    "aholds":     [6,  1000, "number of holds on this ARC buffer"],
93716fd348SMartin Matuska    "dtype":      [27,   -1, "dnode type"],
94716fd348SMartin Matuska    "btype":      [27,   -1, "bonus buffer type"],
95716fd348SMartin Matuska    "data_bs":    [7,  1024, "data block size"],
96716fd348SMartin Matuska    "meta_bs":    [7,  1024, "metadata block size"],
97716fd348SMartin Matuska    "bsize":      [6,  1024, "bonus buffer size"],
98716fd348SMartin Matuska    "lvls":       [6,    -1, "number of indirection levels"],
99716fd348SMartin Matuska    "dholds":     [6,  1000, "number of holds on dnode"],
100716fd348SMartin Matuska    "blocks":     [8,  1000, "number of allocated blocks"],
101716fd348SMartin Matuska    "dsize":      [12, 1024, "size of dnode"],
102716fd348SMartin Matuska    "cached":     [6,  1024, "bytes cached for all blocks"],
103716fd348SMartin Matuska    "direct":     [6,  1024, "bytes cached for direct blocks"],
104716fd348SMartin Matuska    "indirect":   [8,  1024, "bytes cached for indirect blocks"],
105716fd348SMartin Matuska    "bonus":      [5,  1024, "bytes cached for bonus buffer"],
106716fd348SMartin Matuska    "spill":      [5,  1024, "bytes cached for spill block"],
107716fd348SMartin Matuska}
108716fd348SMartin Matuska
109716fd348SMartin Matuskahdr = None
110716fd348SMartin Matuskaxhdr = None
111716fd348SMartin Matuskasep = "  "  # Default separator is 2 spaces
112716fd348SMartin Matuskacmd = ("Usage: dbufstat [-bdhnrtvx] [-i file] [-f fields] [-o file] "
113716fd348SMartin Matuska       "[-s string] [-F filter]\n")
114716fd348SMartin Matuskaraw = 0
115716fd348SMartin Matuska
116716fd348SMartin Matuska
117716fd348SMartin Matuskaif sys.platform.startswith("freebsd"):
118716fd348SMartin Matuska    import io
119716fd348SMartin Matuska    # Requires py-sysctl on FreeBSD
120716fd348SMartin Matuska    import sysctl
121716fd348SMartin Matuska
122716fd348SMartin Matuska    def default_ifile():
123716fd348SMartin Matuska        dbufs = sysctl.filter("kstat.zfs.misc.dbufs")[0].value
124716fd348SMartin Matuska        sys.stdin = io.StringIO(dbufs)
125716fd348SMartin Matuska        return "-"
126716fd348SMartin Matuska
127716fd348SMartin Matuskaelif sys.platform.startswith("linux"):
128716fd348SMartin Matuska    def default_ifile():
129716fd348SMartin Matuska        return "/proc/spl/kstat/zfs/dbufs"
130716fd348SMartin Matuska
131716fd348SMartin Matuska
132716fd348SMartin Matuskadef print_incompat_helper(incompat):
133716fd348SMartin Matuska    cnt = 0
134716fd348SMartin Matuska    for key in sorted(incompat):
135716fd348SMartin Matuska        if cnt == 0:
136716fd348SMartin Matuska            sys.stderr.write("\t")
137716fd348SMartin Matuska        elif cnt > 8:
138716fd348SMartin Matuska            sys.stderr.write(",\n\t")
139716fd348SMartin Matuska            cnt = 0
140716fd348SMartin Matuska        else:
141716fd348SMartin Matuska            sys.stderr.write(", ")
142716fd348SMartin Matuska
143716fd348SMartin Matuska        sys.stderr.write("%s" % key)
144716fd348SMartin Matuska        cnt += 1
145716fd348SMartin Matuska
146716fd348SMartin Matuska    sys.stderr.write("\n\n")
147716fd348SMartin Matuska
148716fd348SMartin Matuska
149716fd348SMartin Matuskadef detailed_usage():
150716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
151716fd348SMartin Matuska
152716fd348SMartin Matuska    sys.stderr.write("Field definitions incompatible with '-b' option:\n")
153716fd348SMartin Matuska    print_incompat_helper(bincompat)
154716fd348SMartin Matuska
155716fd348SMartin Matuska    sys.stderr.write("Field definitions incompatible with '-d' option:\n")
156716fd348SMartin Matuska    print_incompat_helper(dincompat)
157716fd348SMartin Matuska
158716fd348SMartin Matuska    sys.stderr.write("Field definitions incompatible with '-t' option:\n")
159716fd348SMartin Matuska    print_incompat_helper(tincompat)
160716fd348SMartin Matuska
161716fd348SMartin Matuska    sys.stderr.write("Field definitions are as follows:\n")
162716fd348SMartin Matuska    for key in sorted(cols.keys()):
163716fd348SMartin Matuska        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
164716fd348SMartin Matuska    sys.stderr.write("\n")
165716fd348SMartin Matuska
166716fd348SMartin Matuska    sys.exit(0)
167716fd348SMartin Matuska
168716fd348SMartin Matuska
169716fd348SMartin Matuskadef usage():
170716fd348SMartin Matuska    sys.stderr.write("%s\n" % cmd)
171716fd348SMartin Matuska    sys.stderr.write("\t -b : Print table of information for each dbuf\n")
172716fd348SMartin Matuska    sys.stderr.write("\t -d : Print table of information for each dnode\n")
173716fd348SMartin Matuska    sys.stderr.write("\t -h : Print this help message\n")
174716fd348SMartin Matuska    sys.stderr.write("\t -n : Exclude header from output\n")
175716fd348SMartin Matuska    sys.stderr.write("\t -r : Print raw values\n")
176716fd348SMartin Matuska    sys.stderr.write("\t -t : Print table of information for each dnode type"
177716fd348SMartin Matuska                     "\n")
178716fd348SMartin Matuska    sys.stderr.write("\t -v : List all possible field headers and definitions"
179716fd348SMartin Matuska                     "\n")
180716fd348SMartin Matuska    sys.stderr.write("\t -x : Print extended stats\n")
181716fd348SMartin Matuska    sys.stderr.write("\t -i : Redirect input from the specified file\n")
182716fd348SMartin Matuska    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
183716fd348SMartin Matuska    sys.stderr.write("\t -o : Redirect output to the specified file\n")
184716fd348SMartin Matuska    sys.stderr.write("\t -s : Override default field separator with custom "
185716fd348SMartin Matuska                     "character or string\n")
186716fd348SMartin Matuska    sys.stderr.write("\t -F : Filter output by value or regex\n")
187716fd348SMartin Matuska    sys.stderr.write("\nExamples:\n")
188716fd348SMartin Matuska    sys.stderr.write("\tdbufstat -d -o /tmp/d.log\n")
189716fd348SMartin Matuska    sys.stderr.write("\tdbufstat -t -s \",\" -o /tmp/t.log\n")
190716fd348SMartin Matuska    sys.stderr.write("\tdbufstat -v\n")
191716fd348SMartin Matuska    sys.stderr.write("\tdbufstat -d -f pool,object,objset,dsize,cached\n")
192716fd348SMartin Matuska    sys.stderr.write("\tdbufstat -bx -F dbc=1,objset=54,pool=testpool\n")
193716fd348SMartin Matuska    sys.stderr.write("\n")
194716fd348SMartin Matuska
195716fd348SMartin Matuska    sys.exit(1)
196716fd348SMartin Matuska
197716fd348SMartin Matuska
198716fd348SMartin Matuskadef prettynum(sz, scale, num=0):
199716fd348SMartin Matuska    global raw
200716fd348SMartin Matuska
201716fd348SMartin Matuska    suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
202716fd348SMartin Matuska    index = 0
203716fd348SMartin Matuska    save = 0
204716fd348SMartin Matuska
205716fd348SMartin Matuska    if raw or scale == -1:
206716fd348SMartin Matuska        return "%*s" % (sz, num)
207716fd348SMartin Matuska
208716fd348SMartin Matuska    # Rounding error, return 0
209716fd348SMartin Matuska    elif 0 < num < 1:
210716fd348SMartin Matuska        num = 0
211716fd348SMartin Matuska
212716fd348SMartin Matuska    while num > scale and index < 5:
213716fd348SMartin Matuska        save = num
214716fd348SMartin Matuska        num = num / scale
215716fd348SMartin Matuska        index += 1
216716fd348SMartin Matuska
217716fd348SMartin Matuska    if index == 0:
218716fd348SMartin Matuska        return "%*d" % (sz, num)
219716fd348SMartin Matuska
220716fd348SMartin Matuska    if (save / scale) < 10:
221716fd348SMartin Matuska        return "%*.1f%s" % (sz - 1, num, suffix[index])
222716fd348SMartin Matuska    else:
223716fd348SMartin Matuska        return "%*d%s" % (sz - 1, num, suffix[index])
224716fd348SMartin Matuska
225716fd348SMartin Matuska
226716fd348SMartin Matuskadef print_values(v):
227716fd348SMartin Matuska    global hdr
228716fd348SMartin Matuska    global sep
229716fd348SMartin Matuska
230716fd348SMartin Matuska    try:
231716fd348SMartin Matuska        for col in hdr:
232716fd348SMartin Matuska            sys.stdout.write("%s%s" % (
233716fd348SMartin Matuska                prettynum(cols[col][0], cols[col][1], v[col]), sep))
234716fd348SMartin Matuska        sys.stdout.write("\n")
235716fd348SMartin Matuska    except IOError as e:
236716fd348SMartin Matuska        if e.errno == errno.EPIPE:
237716fd348SMartin Matuska            sys.exit(1)
238716fd348SMartin Matuska
239716fd348SMartin Matuska
240716fd348SMartin Matuskadef print_header():
241716fd348SMartin Matuska    global hdr
242716fd348SMartin Matuska    global sep
243716fd348SMartin Matuska
244716fd348SMartin Matuska    try:
245716fd348SMartin Matuska        for col in hdr:
246716fd348SMartin Matuska            sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
247716fd348SMartin Matuska        sys.stdout.write("\n")
248716fd348SMartin Matuska    except IOError as e:
249716fd348SMartin Matuska        if e.errno == errno.EPIPE:
250716fd348SMartin Matuska            sys.exit(1)
251716fd348SMartin Matuska
252716fd348SMartin Matuska
253716fd348SMartin Matuskadef get_typestring(t):
254716fd348SMartin Matuska    ot_strings = [
255716fd348SMartin Matuska                    "DMU_OT_NONE",
256716fd348SMartin Matuska                    # general:
257716fd348SMartin Matuska                    "DMU_OT_OBJECT_DIRECTORY",
258716fd348SMartin Matuska                    "DMU_OT_OBJECT_ARRAY",
259716fd348SMartin Matuska                    "DMU_OT_PACKED_NVLIST",
260716fd348SMartin Matuska                    "DMU_OT_PACKED_NVLIST_SIZE",
261716fd348SMartin Matuska                    "DMU_OT_BPOBJ",
262716fd348SMartin Matuska                    "DMU_OT_BPOBJ_HDR",
263716fd348SMartin Matuska                    # spa:
264716fd348SMartin Matuska                    "DMU_OT_SPACE_MAP_HEADER",
265716fd348SMartin Matuska                    "DMU_OT_SPACE_MAP",
266716fd348SMartin Matuska                    # zil:
267716fd348SMartin Matuska                    "DMU_OT_INTENT_LOG",
268716fd348SMartin Matuska                    # dmu:
269716fd348SMartin Matuska                    "DMU_OT_DNODE",
270716fd348SMartin Matuska                    "DMU_OT_OBJSET",
271716fd348SMartin Matuska                    # dsl:
272716fd348SMartin Matuska                    "DMU_OT_DSL_DIR",
273716fd348SMartin Matuska                    "DMU_OT_DSL_DIR_CHILD_MAP",
274716fd348SMartin Matuska                    "DMU_OT_DSL_DS_SNAP_MAP",
275716fd348SMartin Matuska                    "DMU_OT_DSL_PROPS",
276716fd348SMartin Matuska                    "DMU_OT_DSL_DATASET",
277716fd348SMartin Matuska                    # zpl:
278716fd348SMartin Matuska                    "DMU_OT_ZNODE",
279716fd348SMartin Matuska                    "DMU_OT_OLDACL",
280716fd348SMartin Matuska                    "DMU_OT_PLAIN_FILE_CONTENTS",
281716fd348SMartin Matuska                    "DMU_OT_DIRECTORY_CONTENTS",
282716fd348SMartin Matuska                    "DMU_OT_MASTER_NODE",
283716fd348SMartin Matuska                    "DMU_OT_UNLINKED_SET",
284716fd348SMartin Matuska                    # zvol:
285716fd348SMartin Matuska                    "DMU_OT_ZVOL",
286716fd348SMartin Matuska                    "DMU_OT_ZVOL_PROP",
287716fd348SMartin Matuska                    # other; for testing only!
288716fd348SMartin Matuska                    "DMU_OT_PLAIN_OTHER",
289716fd348SMartin Matuska                    "DMU_OT_UINT64_OTHER",
290716fd348SMartin Matuska                    "DMU_OT_ZAP_OTHER",
291716fd348SMartin Matuska                    # new object types:
292716fd348SMartin Matuska                    "DMU_OT_ERROR_LOG",
293716fd348SMartin Matuska                    "DMU_OT_SPA_HISTORY",
294716fd348SMartin Matuska                    "DMU_OT_SPA_HISTORY_OFFSETS",
295716fd348SMartin Matuska                    "DMU_OT_POOL_PROPS",
296716fd348SMartin Matuska                    "DMU_OT_DSL_PERMS",
297716fd348SMartin Matuska                    "DMU_OT_ACL",
298716fd348SMartin Matuska                    "DMU_OT_SYSACL",
299716fd348SMartin Matuska                    "DMU_OT_FUID",
300716fd348SMartin Matuska                    "DMU_OT_FUID_SIZE",
301716fd348SMartin Matuska                    "DMU_OT_NEXT_CLONES",
302716fd348SMartin Matuska                    "DMU_OT_SCAN_QUEUE",
303716fd348SMartin Matuska                    "DMU_OT_USERGROUP_USED",
304716fd348SMartin Matuska                    "DMU_OT_USERGROUP_QUOTA",
305716fd348SMartin Matuska                    "DMU_OT_USERREFS",
306716fd348SMartin Matuska                    "DMU_OT_DDT_ZAP",
307716fd348SMartin Matuska                    "DMU_OT_DDT_STATS",
308716fd348SMartin Matuska                    "DMU_OT_SA",
309716fd348SMartin Matuska                    "DMU_OT_SA_MASTER_NODE",
310716fd348SMartin Matuska                    "DMU_OT_SA_ATTR_REGISTRATION",
311716fd348SMartin Matuska                    "DMU_OT_SA_ATTR_LAYOUTS",
312716fd348SMartin Matuska                    "DMU_OT_SCAN_XLATE",
313716fd348SMartin Matuska                    "DMU_OT_DEDUP",
314716fd348SMartin Matuska                    "DMU_OT_DEADLIST",
315716fd348SMartin Matuska                    "DMU_OT_DEADLIST_HDR",
316716fd348SMartin Matuska                    "DMU_OT_DSL_CLONES",
317716fd348SMartin Matuska                    "DMU_OT_BPOBJ_SUBOBJ"]
318716fd348SMartin Matuska    otn_strings = {
319716fd348SMartin Matuska                    0x80: "DMU_OTN_UINT8_DATA",
320716fd348SMartin Matuska                    0xc0: "DMU_OTN_UINT8_METADATA",
321716fd348SMartin Matuska                    0x81: "DMU_OTN_UINT16_DATA",
322716fd348SMartin Matuska                    0xc1: "DMU_OTN_UINT16_METADATA",
323716fd348SMartin Matuska                    0x82: "DMU_OTN_UINT32_DATA",
324716fd348SMartin Matuska                    0xc2: "DMU_OTN_UINT32_METADATA",
325716fd348SMartin Matuska                    0x83: "DMU_OTN_UINT64_DATA",
326716fd348SMartin Matuska                    0xc3: "DMU_OTN_UINT64_METADATA",
327716fd348SMartin Matuska                    0x84: "DMU_OTN_ZAP_DATA",
328716fd348SMartin Matuska                    0xc4: "DMU_OTN_ZAP_METADATA",
329716fd348SMartin Matuska                    0xa0: "DMU_OTN_UINT8_ENC_DATA",
330716fd348SMartin Matuska                    0xe0: "DMU_OTN_UINT8_ENC_METADATA",
331716fd348SMartin Matuska                    0xa1: "DMU_OTN_UINT16_ENC_DATA",
332716fd348SMartin Matuska                    0xe1: "DMU_OTN_UINT16_ENC_METADATA",
333716fd348SMartin Matuska                    0xa2: "DMU_OTN_UINT32_ENC_DATA",
334716fd348SMartin Matuska                    0xe2: "DMU_OTN_UINT32_ENC_METADATA",
335716fd348SMartin Matuska                    0xa3: "DMU_OTN_UINT64_ENC_DATA",
336716fd348SMartin Matuska                    0xe3: "DMU_OTN_UINT64_ENC_METADATA",
337716fd348SMartin Matuska                    0xa4: "DMU_OTN_ZAP_ENC_DATA",
338716fd348SMartin Matuska                    0xe4: "DMU_OTN_ZAP_ENC_METADATA"}
339716fd348SMartin Matuska
340716fd348SMartin Matuska    # If "-rr" option is used, don't convert to string representation
341716fd348SMartin Matuska    if raw > 1:
342716fd348SMartin Matuska        return "%i" % t
343716fd348SMartin Matuska
344716fd348SMartin Matuska    try:
345716fd348SMartin Matuska        if t < len(ot_strings):
346716fd348SMartin Matuska            return ot_strings[t]
347716fd348SMartin Matuska        else:
348716fd348SMartin Matuska            return otn_strings[t]
349716fd348SMartin Matuska    except (IndexError, KeyError):
350716fd348SMartin Matuska        return "(UNKNOWN)"
351716fd348SMartin Matuska
352716fd348SMartin Matuska
353716fd348SMartin Matuskadef get_compstring(c):
354716fd348SMartin Matuska    comp_strings = ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
355716fd348SMartin Matuska                    "ZIO_COMPRESS_OFF",     "ZIO_COMPRESS_LZJB",
356716fd348SMartin Matuska                    "ZIO_COMPRESS_EMPTY",   "ZIO_COMPRESS_GZIP_1",
357716fd348SMartin Matuska                    "ZIO_COMPRESS_GZIP_2",  "ZIO_COMPRESS_GZIP_3",
358716fd348SMartin Matuska                    "ZIO_COMPRESS_GZIP_4",  "ZIO_COMPRESS_GZIP_5",
359716fd348SMartin Matuska                    "ZIO_COMPRESS_GZIP_6",  "ZIO_COMPRESS_GZIP_7",
360716fd348SMartin Matuska                    "ZIO_COMPRESS_GZIP_8",  "ZIO_COMPRESS_GZIP_9",
361716fd348SMartin Matuska                    "ZIO_COMPRESS_ZLE",     "ZIO_COMPRESS_LZ4",
362716fd348SMartin Matuska                    "ZIO_COMPRESS_ZSTD",    "ZIO_COMPRESS_FUNCTION"]
363716fd348SMartin Matuska
364716fd348SMartin Matuska    # If "-rr" option is used, don't convert to string representation
365716fd348SMartin Matuska    if raw > 1:
366716fd348SMartin Matuska        return "%i" % c
367716fd348SMartin Matuska
368716fd348SMartin Matuska    try:
369716fd348SMartin Matuska        return comp_strings[c]
370716fd348SMartin Matuska    except IndexError:
371716fd348SMartin Matuska        return "%i" % c
372716fd348SMartin Matuska
373716fd348SMartin Matuska
374716fd348SMartin Matuskadef parse_line(line, labels):
375716fd348SMartin Matuska    global hdr
376716fd348SMartin Matuska
377716fd348SMartin Matuska    new = dict()
378716fd348SMartin Matuska    val = None
379716fd348SMartin Matuska    for col in hdr:
380716fd348SMartin Matuska        # These are "special" fields computed in the update_dict
381716fd348SMartin Matuska        # function, prevent KeyError exception on labels[col] for these.
382716fd348SMartin Matuska        if col not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
383716fd348SMartin Matuska            val = line[labels[col]]
384716fd348SMartin Matuska
385716fd348SMartin Matuska        if col in ['pool', 'flags']:
386716fd348SMartin Matuska            new[col] = str(val)
387716fd348SMartin Matuska        elif col in ['dtype', 'btype']:
388716fd348SMartin Matuska            new[col] = get_typestring(int(val))
389716fd348SMartin Matuska        elif col in ['l2_comp']:
390716fd348SMartin Matuska            new[col] = get_compstring(int(val))
391716fd348SMartin Matuska        else:
392716fd348SMartin Matuska            new[col] = int(val)
393716fd348SMartin Matuska
394716fd348SMartin Matuska    return new
395716fd348SMartin Matuska
396716fd348SMartin Matuska
397716fd348SMartin Matuskadef update_dict(d, k, line, labels):
398716fd348SMartin Matuska    pool = line[labels['pool']]
399716fd348SMartin Matuska    objset = line[labels['objset']]
400716fd348SMartin Matuska    key = line[labels[k]]
401716fd348SMartin Matuska
402716fd348SMartin Matuska    dbsize = int(line[labels['dbsize']])
403*a2b560ccSMartin Matuska    usize = int(line[labels['usize']])
404716fd348SMartin Matuska    blkid = int(line[labels['blkid']])
405716fd348SMartin Matuska    level = int(line[labels['level']])
406716fd348SMartin Matuska
407716fd348SMartin Matuska    if pool not in d:
408716fd348SMartin Matuska        d[pool] = dict()
409716fd348SMartin Matuska
410716fd348SMartin Matuska    if objset not in d[pool]:
411716fd348SMartin Matuska        d[pool][objset] = dict()
412716fd348SMartin Matuska
413716fd348SMartin Matuska    if key not in d[pool][objset]:
414716fd348SMartin Matuska        d[pool][objset][key] = parse_line(line, labels)
415716fd348SMartin Matuska        d[pool][objset][key]['bonus'] = 0
416716fd348SMartin Matuska        d[pool][objset][key]['cached'] = 0
417716fd348SMartin Matuska        d[pool][objset][key]['direct'] = 0
418716fd348SMartin Matuska        d[pool][objset][key]['indirect'] = 0
419716fd348SMartin Matuska        d[pool][objset][key]['spill'] = 0
420716fd348SMartin Matuska
421*a2b560ccSMartin Matuska    d[pool][objset][key]['cached'] += dbsize + usize
422716fd348SMartin Matuska
423716fd348SMartin Matuska    if blkid == -1:
424716fd348SMartin Matuska        d[pool][objset][key]['bonus'] += dbsize
425716fd348SMartin Matuska    elif blkid == -2:
426716fd348SMartin Matuska        d[pool][objset][key]['spill'] += dbsize
427716fd348SMartin Matuska    else:
428716fd348SMartin Matuska        if level == 0:
429716fd348SMartin Matuska            d[pool][objset][key]['direct'] += dbsize
430716fd348SMartin Matuska        else:
431716fd348SMartin Matuska            d[pool][objset][key]['indirect'] += dbsize
432716fd348SMartin Matuska
433716fd348SMartin Matuska    return d
434716fd348SMartin Matuska
435716fd348SMartin Matuska
436716fd348SMartin Matuskadef skip_line(vals, filters):
437716fd348SMartin Matuska    '''
438716fd348SMartin Matuska    Determines if a line should be skipped during printing
439716fd348SMartin Matuska    based on a set of filters
440716fd348SMartin Matuska    '''
441716fd348SMartin Matuska    if len(filters) == 0:
442716fd348SMartin Matuska        return False
443716fd348SMartin Matuska
444716fd348SMartin Matuska    for key in vals:
445716fd348SMartin Matuska        if key in filters:
446716fd348SMartin Matuska            val = prettynum(cols[key][0], cols[key][1], vals[key]).strip()
447716fd348SMartin Matuska            # we want a full match here
448716fd348SMartin Matuska            if re.match("(?:" + filters[key] + r")\Z", val) is None:
449716fd348SMartin Matuska                return True
450716fd348SMartin Matuska
451716fd348SMartin Matuska    return False
452716fd348SMartin Matuska
453716fd348SMartin Matuska
454716fd348SMartin Matuskadef print_dict(d, filters, noheader):
455716fd348SMartin Matuska    if not noheader:
456716fd348SMartin Matuska        print_header()
457716fd348SMartin Matuska    for pool in list(d.keys()):
458716fd348SMartin Matuska        for objset in list(d[pool].keys()):
459716fd348SMartin Matuska            for v in list(d[pool][objset].values()):
460716fd348SMartin Matuska                if not skip_line(v, filters):
461716fd348SMartin Matuska                    print_values(v)
462716fd348SMartin Matuska
463716fd348SMartin Matuska
464716fd348SMartin Matuskadef dnodes_build_dict(filehandle):
465716fd348SMartin Matuska    labels = dict()
466716fd348SMartin Matuska    dnodes = dict()
467716fd348SMartin Matuska
468716fd348SMartin Matuska    # First 3 lines are header information, skip the first two
469716fd348SMartin Matuska    for i in range(2):
470716fd348SMartin Matuska        next(filehandle)
471716fd348SMartin Matuska
472716fd348SMartin Matuska    # The third line contains the labels and index locations
473716fd348SMartin Matuska    for i, v in enumerate(next(filehandle).split()):
474716fd348SMartin Matuska        labels[v] = i
475716fd348SMartin Matuska
476716fd348SMartin Matuska    # The rest of the file is buffer information
477716fd348SMartin Matuska    for line in filehandle:
478716fd348SMartin Matuska        update_dict(dnodes, 'object', line.split(), labels)
479716fd348SMartin Matuska
480716fd348SMartin Matuska    return dnodes
481716fd348SMartin Matuska
482716fd348SMartin Matuska
483716fd348SMartin Matuskadef types_build_dict(filehandle):
484716fd348SMartin Matuska    labels = dict()
485716fd348SMartin Matuska    types = dict()
486716fd348SMartin Matuska
487716fd348SMartin Matuska    # First 3 lines are header information, skip the first two
488716fd348SMartin Matuska    for i in range(2):
489716fd348SMartin Matuska        next(filehandle)
490716fd348SMartin Matuska
491716fd348SMartin Matuska    # The third line contains the labels and index locations
492716fd348SMartin Matuska    for i, v in enumerate(next(filehandle).split()):
493716fd348SMartin Matuska        labels[v] = i
494716fd348SMartin Matuska
495716fd348SMartin Matuska    # The rest of the file is buffer information
496716fd348SMartin Matuska    for line in filehandle:
497716fd348SMartin Matuska        update_dict(types, 'dtype', line.split(), labels)
498716fd348SMartin Matuska
499716fd348SMartin Matuska    return types
500716fd348SMartin Matuska
501716fd348SMartin Matuska
502716fd348SMartin Matuskadef buffers_print_all(filehandle, filters, noheader):
503716fd348SMartin Matuska    labels = dict()
504716fd348SMartin Matuska
505716fd348SMartin Matuska    # First 3 lines are header information, skip the first two
506716fd348SMartin Matuska    for i in range(2):
507716fd348SMartin Matuska        next(filehandle)
508716fd348SMartin Matuska
509716fd348SMartin Matuska    # The third line contains the labels and index locations
510716fd348SMartin Matuska    for i, v in enumerate(next(filehandle).split()):
511716fd348SMartin Matuska        labels[v] = i
512716fd348SMartin Matuska
513716fd348SMartin Matuska    if not noheader:
514716fd348SMartin Matuska        print_header()
515716fd348SMartin Matuska
516716fd348SMartin Matuska    # The rest of the file is buffer information
517716fd348SMartin Matuska    for line in filehandle:
518716fd348SMartin Matuska        vals = parse_line(line.split(), labels)
519716fd348SMartin Matuska        if not skip_line(vals, filters):
520716fd348SMartin Matuska            print_values(vals)
521716fd348SMartin Matuska
522716fd348SMartin Matuska
523716fd348SMartin Matuskadef main():
524716fd348SMartin Matuska    global hdr
525716fd348SMartin Matuska    global sep
526716fd348SMartin Matuska    global raw
527716fd348SMartin Matuska
528716fd348SMartin Matuska    desired_cols = None
529716fd348SMartin Matuska    bflag = False
530716fd348SMartin Matuska    dflag = False
531716fd348SMartin Matuska    hflag = False
532716fd348SMartin Matuska    ifile = None
533716fd348SMartin Matuska    ofile = None
534716fd348SMartin Matuska    tflag = False
535716fd348SMartin Matuska    vflag = False
536716fd348SMartin Matuska    xflag = False
537716fd348SMartin Matuska    nflag = False
538716fd348SMartin Matuska    filters = dict()
539716fd348SMartin Matuska
540716fd348SMartin Matuska    try:
541716fd348SMartin Matuska        opts, args = getopt.getopt(
542716fd348SMartin Matuska            sys.argv[1:],
543716fd348SMartin Matuska            "bdf:hi:o:rs:tvxF:n",
544716fd348SMartin Matuska            [
545716fd348SMartin Matuska                "buffers",
546716fd348SMartin Matuska                "dnodes",
547716fd348SMartin Matuska                "columns",
548716fd348SMartin Matuska                "help",
549716fd348SMartin Matuska                "infile",
550716fd348SMartin Matuska                "outfile",
551716fd348SMartin Matuska                "separator",
552716fd348SMartin Matuska                "types",
553716fd348SMartin Matuska                "verbose",
554716fd348SMartin Matuska                "extended",
555716fd348SMartin Matuska                "filter"
556716fd348SMartin Matuska            ]
557716fd348SMartin Matuska        )
558716fd348SMartin Matuska    except getopt.error:
559716fd348SMartin Matuska        usage()
560716fd348SMartin Matuska        opts = None
561716fd348SMartin Matuska
562716fd348SMartin Matuska    for opt, arg in opts:
563716fd348SMartin Matuska        if opt in ('-b', '--buffers'):
564716fd348SMartin Matuska            bflag = True
565716fd348SMartin Matuska        if opt in ('-d', '--dnodes'):
566716fd348SMartin Matuska            dflag = True
567716fd348SMartin Matuska        if opt in ('-f', '--columns'):
568716fd348SMartin Matuska            desired_cols = arg
569716fd348SMartin Matuska        if opt in ('-h', '--help'):
570716fd348SMartin Matuska            hflag = True
571716fd348SMartin Matuska        if opt in ('-i', '--infile'):
572716fd348SMartin Matuska            ifile = arg
573716fd348SMartin Matuska        if opt in ('-o', '--outfile'):
574716fd348SMartin Matuska            ofile = arg
575716fd348SMartin Matuska        if opt in ('-r', '--raw'):
576716fd348SMartin Matuska            raw += 1
577716fd348SMartin Matuska        if opt in ('-s', '--separator'):
578716fd348SMartin Matuska            sep = arg
579716fd348SMartin Matuska        if opt in ('-t', '--types'):
580716fd348SMartin Matuska            tflag = True
581716fd348SMartin Matuska        if opt in ('-v', '--verbose'):
582716fd348SMartin Matuska            vflag = True
583716fd348SMartin Matuska        if opt in ('-x', '--extended'):
584716fd348SMartin Matuska            xflag = True
585716fd348SMartin Matuska        if opt in ('-n', '--noheader'):
586716fd348SMartin Matuska            nflag = True
587716fd348SMartin Matuska        if opt in ('-F', '--filter'):
588716fd348SMartin Matuska            fils = [x.strip() for x in arg.split(",")]
589716fd348SMartin Matuska
590716fd348SMartin Matuska            for fil in fils:
591716fd348SMartin Matuska                f = [x.strip() for x in fil.split("=")]
592716fd348SMartin Matuska
593716fd348SMartin Matuska                if len(f) != 2:
594716fd348SMartin Matuska                    sys.stderr.write("Invalid filter '%s'.\n" % fil)
595716fd348SMartin Matuska                    sys.exit(1)
596716fd348SMartin Matuska
597716fd348SMartin Matuska                if f[0] not in cols:
598716fd348SMartin Matuska                    sys.stderr.write("Invalid field '%s' in filter.\n" % f[0])
599716fd348SMartin Matuska                    sys.exit(1)
600716fd348SMartin Matuska
601716fd348SMartin Matuska                if f[0] in filters:
602716fd348SMartin Matuska                    sys.stderr.write("Field '%s' specified multiple times in "
603716fd348SMartin Matuska                                     "filter.\n" % f[0])
604716fd348SMartin Matuska                    sys.exit(1)
605716fd348SMartin Matuska
606716fd348SMartin Matuska                try:
607716fd348SMartin Matuska                    re.compile("(?:" + f[1] + r")\Z")
608716fd348SMartin Matuska                except re.error:
609716fd348SMartin Matuska                    sys.stderr.write("Invalid regex for field '%s' in "
610716fd348SMartin Matuska                                     "filter.\n" % f[0])
611716fd348SMartin Matuska                    sys.exit(1)
612716fd348SMartin Matuska
613716fd348SMartin Matuska                filters[f[0]] = f[1]
614716fd348SMartin Matuska
615716fd348SMartin Matuska    if hflag or (xflag and desired_cols):
616716fd348SMartin Matuska        usage()
617716fd348SMartin Matuska
618716fd348SMartin Matuska    if vflag:
619716fd348SMartin Matuska        detailed_usage()
620716fd348SMartin Matuska
621716fd348SMartin Matuska    # Ensure at most only one of b, d, or t flags are set
622716fd348SMartin Matuska    if (bflag and dflag) or (bflag and tflag) or (dflag and tflag):
623716fd348SMartin Matuska        usage()
624716fd348SMartin Matuska
625716fd348SMartin Matuska    if bflag:
626716fd348SMartin Matuska        hdr = bxhdr if xflag else bhdr
627716fd348SMartin Matuska    elif tflag:
628716fd348SMartin Matuska        hdr = txhdr if xflag else thdr
629716fd348SMartin Matuska    else:  # Even if dflag is False, it's the default if none set
630716fd348SMartin Matuska        dflag = True
631716fd348SMartin Matuska        hdr = dxhdr if xflag else dhdr
632716fd348SMartin Matuska
633716fd348SMartin Matuska    if desired_cols:
634716fd348SMartin Matuska        hdr = desired_cols.split(",")
635716fd348SMartin Matuska
636716fd348SMartin Matuska        invalid = []
637716fd348SMartin Matuska        incompat = []
638716fd348SMartin Matuska        for ele in hdr:
639716fd348SMartin Matuska            if ele not in cols:
640716fd348SMartin Matuska                invalid.append(ele)
641716fd348SMartin Matuska            elif ((bflag and bincompat and ele in bincompat) or
642716fd348SMartin Matuska                  (dflag and dincompat and ele in dincompat) or
643716fd348SMartin Matuska                  (tflag and tincompat and ele in tincompat)):
644716fd348SMartin Matuska                    incompat.append(ele)
645716fd348SMartin Matuska
646716fd348SMartin Matuska        if len(invalid) > 0:
647716fd348SMartin Matuska            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
648716fd348SMartin Matuska            usage()
649716fd348SMartin Matuska
650716fd348SMartin Matuska        if len(incompat) > 0:
651716fd348SMartin Matuska            sys.stderr.write("Incompatible field specified! -- %s\n" %
652716fd348SMartin Matuska                             incompat)
653716fd348SMartin Matuska            usage()
654716fd348SMartin Matuska
655716fd348SMartin Matuska    if ofile:
656716fd348SMartin Matuska        try:
657716fd348SMartin Matuska            tmp = open(ofile, "w")
658716fd348SMartin Matuska            sys.stdout = tmp
659716fd348SMartin Matuska
660716fd348SMartin Matuska        except IOError:
661716fd348SMartin Matuska            sys.stderr.write("Cannot open %s for writing\n" % ofile)
662716fd348SMartin Matuska            sys.exit(1)
663716fd348SMartin Matuska
664716fd348SMartin Matuska    if not ifile:
665716fd348SMartin Matuska        ifile = default_ifile()
666716fd348SMartin Matuska
667716fd348SMartin Matuska    if ifile != "-":
668716fd348SMartin Matuska        try:
669716fd348SMartin Matuska            tmp = open(ifile, "r")
670716fd348SMartin Matuska            sys.stdin = tmp
671716fd348SMartin Matuska        except IOError:
672716fd348SMartin Matuska            sys.stderr.write("Cannot open %s for reading\n" % ifile)
673716fd348SMartin Matuska            sys.exit(1)
674716fd348SMartin Matuska
675716fd348SMartin Matuska    if bflag:
676716fd348SMartin Matuska        buffers_print_all(sys.stdin, filters, nflag)
677716fd348SMartin Matuska
678716fd348SMartin Matuska    if dflag:
679716fd348SMartin Matuska        print_dict(dnodes_build_dict(sys.stdin), filters, nflag)
680716fd348SMartin Matuska
681716fd348SMartin Matuska    if tflag:
682716fd348SMartin Matuska        print_dict(types_build_dict(sys.stdin), filters, nflag)
683716fd348SMartin Matuska
684716fd348SMartin Matuska
685716fd348SMartin Matuskaif __name__ == '__main__':
686716fd348SMartin Matuska    main()
687