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