]> granicus.if.org Git - zfs/blob - cmd/dbufstat/dbufstat.py
pyzfs: python3 support (unit tests)
[zfs] / cmd / dbufstat / dbufstat.py
1 #!/usr/bin/python
2 #
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.
6 #
7 # CDDL HEADER START
8 #
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
12 # with the License.
13 #
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.
18 #
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]
24 #
25 # CDDL HEADER END
26 #
27 # Copyright (C) 2013 Lawrence Livermore National Security, LLC.
28 # Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
29 #
30
31 import sys
32 import getopt
33 import errno
34 import re
35
36 bhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
37 bxhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
38          "meta", "state", "dbholds", "dbc", "list", "atype", "flags",
39          "count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
40          "l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
41          "data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
42 bincompat = ["cached", "direct", "indirect", "bonus", "spill"]
43
44 dhdr = ["pool", "objset", "object", "dtype", "cached"]
45 dxhdr = ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
46          "bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
47          "indirect", "bonus", "spill"]
48 dincompat = ["level", "blkid", "offset", "dbsize", "meta", "state", "dbholds",
49              "dbc", "list", "atype", "flags", "count", "asize", "access",
50              "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr", "l2_asize",
51              "l2_comp", "aholds"]
52
53 thdr = ["pool", "objset", "dtype", "cached"]
54 txhdr = ["pool", "objset", "dtype", "cached", "direct", "indirect",
55          "bonus", "spill"]
56 tincompat = ["object", "level", "blkid", "offset", "dbsize", "meta", "state",
57              "dbc", "dbholds", "list", "atype", "flags", "count", "asize",
58              "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
59              "l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
60              "bsize", "lvls", "dholds", "blocks", "dsize"]
61
62 cols = {
63     # hdr:        [size, scale, description]
64     "pool":       [15,   -1, "pool name"],
65     "objset":     [6,    -1, "dataset identification number"],
66     "object":     [10,   -1, "object number"],
67     "level":      [5,    -1, "indirection level of buffer"],
68     "blkid":      [8,    -1, "block number of buffer"],
69     "offset":     [12, 1024, "offset in object of buffer"],
70     "dbsize":     [7,  1024, "size of buffer"],
71     "meta":       [4,    -1, "is this buffer metadata?"],
72     "state":      [5,    -1, "state of buffer (read, cached, etc)"],
73     "dbholds":    [7,  1000, "number of holds on buffer"],
74     "dbc":        [3,    -1, "in dbuf cache"],
75     "list":       [4,    -1, "which ARC list contains this buffer"],
76     "atype":      [7,    -1, "ARC header type (data or metadata)"],
77     "flags":      [9,    -1, "ARC read flags"],
78     "count":      [5,    -1, "ARC data count"],
79     "asize":      [7,  1024, "size of this ARC buffer"],
80     "access":     [10,   -1, "time this ARC buffer was last accessed"],
81     "mru":        [5,  1000, "hits while on the ARC's MRU list"],
82     "gmru":       [5,  1000, "hits while on the ARC's MRU ghost list"],
83     "mfu":        [5,  1000, "hits while on the ARC's MFU list"],
84     "gmfu":       [5,  1000, "hits while on the ARC's MFU ghost list"],
85     "l2":         [5,  1000, "hits while on the L2ARC"],
86     "l2_dattr":   [8,    -1, "L2ARC disk address/offset"],
87     "l2_asize":   [8,  1024, "L2ARC alloc'd size (depending on compression)"],
88     "l2_comp":    [21,   -1, "L2ARC compression algorithm for buffer"],
89     "aholds":     [6,  1000, "number of holds on this ARC buffer"],
90     "dtype":      [27,   -1, "dnode type"],
91     "btype":      [27,   -1, "bonus buffer type"],
92     "data_bs":    [7,  1024, "data block size"],
93     "meta_bs":    [7,  1024, "metadata block size"],
94     "bsize":      [6,  1024, "bonus buffer size"],
95     "lvls":       [6,    -1, "number of indirection levels"],
96     "dholds":     [6,  1000, "number of holds on dnode"],
97     "blocks":     [8,  1000, "number of allocated blocks"],
98     "dsize":      [12, 1024, "size of dnode"],
99     "cached":     [6,  1024, "bytes cached for all blocks"],
100     "direct":     [6,  1024, "bytes cached for direct blocks"],
101     "indirect":   [8,  1024, "bytes cached for indirect blocks"],
102     "bonus":      [5,  1024, "bytes cached for bonus buffer"],
103     "spill":      [5,  1024, "bytes cached for spill block"],
104 }
105
106 hdr = None
107 xhdr = None
108 sep = "  "  # Default separator is 2 spaces
109 cmd = ("Usage: dbufstat.py [-bdhnrtvx] [-i file] [-f fields] [-o file] "
110        "[-s string] [-F filter]\n")
111 raw = 0
112
113
114 def print_incompat_helper(incompat):
115     cnt = 0
116     for key in sorted(incompat):
117         if cnt is 0:
118             sys.stderr.write("\t")
119         elif cnt > 8:
120             sys.stderr.write(",\n\t")
121             cnt = 0
122         else:
123             sys.stderr.write(", ")
124
125         sys.stderr.write("%s" % key)
126         cnt += 1
127
128     sys.stderr.write("\n\n")
129
130
131 def detailed_usage():
132     sys.stderr.write("%s\n" % cmd)
133
134     sys.stderr.write("Field definitions incompatible with '-b' option:\n")
135     print_incompat_helper(bincompat)
136
137     sys.stderr.write("Field definitions incompatible with '-d' option:\n")
138     print_incompat_helper(dincompat)
139
140     sys.stderr.write("Field definitions incompatible with '-t' option:\n")
141     print_incompat_helper(tincompat)
142
143     sys.stderr.write("Field definitions are as follows:\n")
144     for key in sorted(cols.keys()):
145         sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
146     sys.stderr.write("\n")
147
148     sys.exit(0)
149
150
151 def usage():
152     sys.stderr.write("%s\n" % cmd)
153     sys.stderr.write("\t -b : Print table of information for each dbuf\n")
154     sys.stderr.write("\t -d : Print table of information for each dnode\n")
155     sys.stderr.write("\t -h : Print this help message\n")
156     sys.stderr.write("\t -n : Exclude header from output\n")
157     sys.stderr.write("\t -r : Print raw values\n")
158     sys.stderr.write("\t -t : Print table of information for each dnode type"
159                      "\n")
160     sys.stderr.write("\t -v : List all possible field headers and definitions"
161                      "\n")
162     sys.stderr.write("\t -x : Print extended stats\n")
163     sys.stderr.write("\t -i : Redirect input from the specified file\n")
164     sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
165     sys.stderr.write("\t -o : Redirect output to the specified file\n")
166     sys.stderr.write("\t -s : Override default field separator with custom "
167                      "character or string\n")
168     sys.stderr.write("\t -F : Filter output by value or regex\n")
169     sys.stderr.write("\nExamples:\n")
170     sys.stderr.write("\tdbufstat.py -d -o /tmp/d.log\n")
171     sys.stderr.write("\tdbufstat.py -t -s \",\" -o /tmp/t.log\n")
172     sys.stderr.write("\tdbufstat.py -v\n")
173     sys.stderr.write("\tdbufstat.py -d -f pool,object,objset,dsize,cached\n")
174     sys.stderr.write("\tdbufstat.py -bx -F dbc=1,objset=54,pool=testpool\n")
175     sys.stderr.write("\n")
176
177     sys.exit(1)
178
179
180 def prettynum(sz, scale, num=0):
181     global raw
182
183     suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
184     index = 0
185     save = 0
186
187     if raw or scale == -1:
188         return "%*s" % (sz, num)
189
190     # Rounding error, return 0
191     elif 0 < num < 1:
192         num = 0
193
194     while num > scale and index < 5:
195         save = num
196         num = num / scale
197         index += 1
198
199     if index == 0:
200         return "%*d" % (sz, num)
201
202     if (save / scale) < 10:
203         return "%*.1f%s" % (sz - 1, num, suffix[index])
204     else:
205         return "%*d%s" % (sz - 1, num, suffix[index])
206
207
208 def print_values(v):
209     global hdr
210     global sep
211
212     try:
213         for col in hdr:
214             sys.stdout.write("%s%s" % (
215                 prettynum(cols[col][0], cols[col][1], v[col]), sep))
216         sys.stdout.write("\n")
217     except IOError as e:
218         if e.errno == errno.EPIPE:
219             sys.exit(1)
220
221
222 def print_header():
223     global hdr
224     global sep
225
226     try:
227         for col in hdr:
228             sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
229         sys.stdout.write("\n")
230     except IOError as e:
231         if e.errno == errno.EPIPE:
232             sys.exit(1)
233
234
235 def get_typestring(t):
236     ot_strings = [
237                     "DMU_OT_NONE",
238                     # general:
239                     "DMU_OT_OBJECT_DIRECTORY",
240                     "DMU_OT_OBJECT_ARRAY",
241                     "DMU_OT_PACKED_NVLIST",
242                     "DMU_OT_PACKED_NVLIST_SIZE",
243                     "DMU_OT_BPOBJ",
244                     "DMU_OT_BPOBJ_HDR",
245                     # spa:
246                     "DMU_OT_SPACE_MAP_HEADER",
247                     "DMU_OT_SPACE_MAP",
248                     # zil:
249                     "DMU_OT_INTENT_LOG",
250                     # dmu:
251                     "DMU_OT_DNODE",
252                     "DMU_OT_OBJSET",
253                     # dsl:
254                     "DMU_OT_DSL_DIR",
255                     "DMU_OT_DSL_DIR_CHILD_MAP",
256                     "DMU_OT_DSL_DS_SNAP_MAP",
257                     "DMU_OT_DSL_PROPS",
258                     "DMU_OT_DSL_DATASET",
259                     # zpl:
260                     "DMU_OT_ZNODE",
261                     "DMU_OT_OLDACL",
262                     "DMU_OT_PLAIN_FILE_CONTENTS",
263                     "DMU_OT_DIRECTORY_CONTENTS",
264                     "DMU_OT_MASTER_NODE",
265                     "DMU_OT_UNLINKED_SET",
266                     # zvol:
267                     "DMU_OT_ZVOL",
268                     "DMU_OT_ZVOL_PROP",
269                     # other; for testing only!
270                     "DMU_OT_PLAIN_OTHER",
271                     "DMU_OT_UINT64_OTHER",
272                     "DMU_OT_ZAP_OTHER",
273                     # new object types:
274                     "DMU_OT_ERROR_LOG",
275                     "DMU_OT_SPA_HISTORY",
276                     "DMU_OT_SPA_HISTORY_OFFSETS",
277                     "DMU_OT_POOL_PROPS",
278                     "DMU_OT_DSL_PERMS",
279                     "DMU_OT_ACL",
280                     "DMU_OT_SYSACL",
281                     "DMU_OT_FUID",
282                     "DMU_OT_FUID_SIZE",
283                     "DMU_OT_NEXT_CLONES",
284                     "DMU_OT_SCAN_QUEUE",
285                     "DMU_OT_USERGROUP_USED",
286                     "DMU_OT_USERGROUP_QUOTA",
287                     "DMU_OT_USERREFS",
288                     "DMU_OT_DDT_ZAP",
289                     "DMU_OT_DDT_STATS",
290                     "DMU_OT_SA",
291                     "DMU_OT_SA_MASTER_NODE",
292                     "DMU_OT_SA_ATTR_REGISTRATION",
293                     "DMU_OT_SA_ATTR_LAYOUTS",
294                     "DMU_OT_SCAN_XLATE",
295                     "DMU_OT_DEDUP",
296                     "DMU_OT_DEADLIST",
297                     "DMU_OT_DEADLIST_HDR",
298                     "DMU_OT_DSL_CLONES",
299                     "DMU_OT_BPOBJ_SUBOBJ"]
300     otn_strings = {
301                     0x80: "DMU_OTN_UINT8_DATA",
302                     0xc0: "DMU_OTN_UINT8_METADATA",
303                     0x81: "DMU_OTN_UINT16_DATA",
304                     0xc1: "DMU_OTN_UINT16_METADATA",
305                     0x82: "DMU_OTN_UINT32_DATA",
306                     0xc2: "DMU_OTN_UINT32_METADATA",
307                     0x83: "DMU_OTN_UINT64_DATA",
308                     0xc3: "DMU_OTN_UINT64_METADATA",
309                     0x84: "DMU_OTN_ZAP_DATA",
310                     0xc4: "DMU_OTN_ZAP_METADATA",
311                     0xa0: "DMU_OTN_UINT8_ENC_DATA",
312                     0xe0: "DMU_OTN_UINT8_ENC_METADATA",
313                     0xa1: "DMU_OTN_UINT16_ENC_DATA",
314                     0xe1: "DMU_OTN_UINT16_ENC_METADATA",
315                     0xa2: "DMU_OTN_UINT32_ENC_DATA",
316                     0xe2: "DMU_OTN_UINT32_ENC_METADATA",
317                     0xa3: "DMU_OTN_UINT64_ENC_DATA",
318                     0xe3: "DMU_OTN_UINT64_ENC_METADATA",
319                     0xa4: "DMU_OTN_ZAP_ENC_DATA",
320                     0xe4: "DMU_OTN_ZAP_ENC_METADATA"}
321
322     # If "-rr" option is used, don't convert to string representation
323     if raw > 1:
324         return "%i" % t
325
326     try:
327         if t < len(ot_strings):
328             return ot_strings[t]
329         else:
330             return otn_strings[t]
331     except (IndexError, KeyError):
332         return "(UNKNOWN)"
333
334
335 def get_compstring(c):
336     comp_strings = ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
337                     "ZIO_COMPRESS_OFF",     "ZIO_COMPRESS_LZJB",
338                     "ZIO_COMPRESS_EMPTY",   "ZIO_COMPRESS_GZIP_1",
339                     "ZIO_COMPRESS_GZIP_2",  "ZIO_COMPRESS_GZIP_3",
340                     "ZIO_COMPRESS_GZIP_4",  "ZIO_COMPRESS_GZIP_5",
341                     "ZIO_COMPRESS_GZIP_6",  "ZIO_COMPRESS_GZIP_7",
342                     "ZIO_COMPRESS_GZIP_8",  "ZIO_COMPRESS_GZIP_9",
343                     "ZIO_COMPRESS_ZLE",     "ZIO_COMPRESS_LZ4",
344                     "ZIO_COMPRESS_FUNCTION"]
345
346     # If "-rr" option is used, don't convert to string representation
347     if raw > 1:
348         return "%i" % c
349
350     try:
351         return comp_strings[c]
352     except IndexError:
353         return "%i" % c
354
355
356 def parse_line(line, labels):
357     global hdr
358
359     new = dict()
360     val = None
361     for col in hdr:
362         # These are "special" fields computed in the update_dict
363         # function, prevent KeyError exception on labels[col] for these.
364         if col not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
365             val = line[labels[col]]
366
367         if col in ['pool', 'flags']:
368             new[col] = str(val)
369         elif col in ['dtype', 'btype']:
370             new[col] = get_typestring(int(val))
371         elif col in ['l2_comp']:
372             new[col] = get_compstring(int(val))
373         else:
374             new[col] = int(val)
375
376     return new
377
378
379 def update_dict(d, k, line, labels):
380     pool = line[labels['pool']]
381     objset = line[labels['objset']]
382     key = line[labels[k]]
383
384     dbsize = int(line[labels['dbsize']])
385     blkid = int(line[labels['blkid']])
386     level = int(line[labels['level']])
387
388     if pool not in d:
389         d[pool] = dict()
390
391     if objset not in d[pool]:
392         d[pool][objset] = dict()
393
394     if key not in d[pool][objset]:
395         d[pool][objset][key] = parse_line(line, labels)
396         d[pool][objset][key]['bonus'] = 0
397         d[pool][objset][key]['cached'] = 0
398         d[pool][objset][key]['direct'] = 0
399         d[pool][objset][key]['indirect'] = 0
400         d[pool][objset][key]['spill'] = 0
401
402     d[pool][objset][key]['cached'] += dbsize
403
404     if blkid == -1:
405         d[pool][objset][key]['bonus'] += dbsize
406     elif blkid == -2:
407         d[pool][objset][key]['spill'] += dbsize
408     else:
409         if level == 0:
410             d[pool][objset][key]['direct'] += dbsize
411         else:
412             d[pool][objset][key]['indirect'] += dbsize
413
414     return d
415
416
417 def skip_line(vals, filters):
418     '''
419     Determines if a line should be skipped during printing
420     based on a set of filters
421     '''
422     if len(filters) == 0:
423         return False
424
425     for key in vals:
426         if key in filters:
427             val = prettynum(cols[key][0], cols[key][1], vals[key]).strip()
428             # we want a full match here
429             if re.match("(?:" + filters[key] + r")\Z", val) is None:
430                 return True
431
432     return False
433
434
435 def print_dict(d, filters, noheader):
436     if not noheader:
437         print_header()
438     for pool in list(d.keys()):
439         for objset in list(d[pool].keys()):
440             for v in list(d[pool][objset].values()):
441                 if not skip_line(v, filters):
442                     print_values(v)
443
444
445 def dnodes_build_dict(filehandle):
446     labels = dict()
447     dnodes = dict()
448
449     # First 3 lines are header information, skip the first two
450     for i in range(2):
451         next(filehandle)
452
453     # The third line contains the labels and index locations
454     for i, v in enumerate(next(filehandle).split()):
455         labels[v] = i
456
457     # The rest of the file is buffer information
458     for line in filehandle:
459         update_dict(dnodes, 'object', line.split(), labels)
460
461     return dnodes
462
463
464 def types_build_dict(filehandle):
465     labels = dict()
466     types = dict()
467
468     # First 3 lines are header information, skip the first two
469     for i in range(2):
470         next(filehandle)
471
472     # The third line contains the labels and index locations
473     for i, v in enumerate(next(filehandle).split()):
474         labels[v] = i
475
476     # The rest of the file is buffer information
477     for line in filehandle:
478         update_dict(types, 'dtype', line.split(), labels)
479
480     return types
481
482
483 def buffers_print_all(filehandle, filters, noheader):
484     labels = dict()
485
486     # First 3 lines are header information, skip the first two
487     for i in range(2):
488         next(filehandle)
489
490     # The third line contains the labels and index locations
491     for i, v in enumerate(next(filehandle).split()):
492         labels[v] = i
493
494     if not noheader:
495         print_header()
496
497     # The rest of the file is buffer information
498     for line in filehandle:
499         vals = parse_line(line.split(), labels)
500         if not skip_line(vals, filters):
501             print_values(vals)
502
503
504 def main():
505     global hdr
506     global sep
507     global raw
508
509     desired_cols = None
510     bflag = False
511     dflag = False
512     hflag = False
513     ifile = None
514     ofile = None
515     tflag = False
516     vflag = False
517     xflag = False
518     nflag = False
519     filters = dict()
520
521     try:
522         opts, args = getopt.getopt(
523             sys.argv[1:],
524             "bdf:hi:o:rs:tvxF:n",
525             [
526                 "buffers",
527                 "dnodes",
528                 "columns",
529                 "help",
530                 "infile",
531                 "outfile",
532                 "separator",
533                 "types",
534                 "verbose",
535                 "extended",
536                 "filter"
537             ]
538         )
539     except getopt.error:
540         usage()
541         opts = None
542
543     for opt, arg in opts:
544         if opt in ('-b', '--buffers'):
545             bflag = True
546         if opt in ('-d', '--dnodes'):
547             dflag = True
548         if opt in ('-f', '--columns'):
549             desired_cols = arg
550         if opt in ('-h', '--help'):
551             hflag = True
552         if opt in ('-i', '--infile'):
553             ifile = arg
554         if opt in ('-o', '--outfile'):
555             ofile = arg
556         if opt in ('-r', '--raw'):
557             raw += 1
558         if opt in ('-s', '--separator'):
559             sep = arg
560         if opt in ('-t', '--types'):
561             tflag = True
562         if opt in ('-v', '--verbose'):
563             vflag = True
564         if opt in ('-x', '--extended'):
565             xflag = True
566         if opt in ('-n', '--noheader'):
567             nflag = True
568         if opt in ('-F', '--filter'):
569             fils = [x.strip() for x in arg.split(",")]
570
571             for fil in fils:
572                 f = [x.strip() for x in fil.split("=")]
573
574                 if len(f) != 2:
575                     sys.stderr.write("Invalid filter '%s'.\n" % fil)
576                     sys.exit(1)
577
578                 if f[0] not in cols:
579                     sys.stderr.write("Invalid field '%s' in filter.\n" % f[0])
580                     sys.exit(1)
581
582                 if f[0] in filters:
583                     sys.stderr.write("Field '%s' specified multiple times in "
584                                      "filter.\n" % f[0])
585                     sys.exit(1)
586
587                 try:
588                     re.compile("(?:" + f[1] + r")\Z")
589                 except re.error:
590                     sys.stderr.write("Invalid regex for field '%s' in "
591                                      "filter.\n" % f[0])
592                     sys.exit(1)
593
594                 filters[f[0]] = f[1]
595
596     if hflag or (xflag and desired_cols):
597         usage()
598
599     if vflag:
600         detailed_usage()
601
602     # Ensure at most only one of b, d, or t flags are set
603     if (bflag and dflag) or (bflag and tflag) or (dflag and tflag):
604         usage()
605
606     if bflag:
607         hdr = bxhdr if xflag else bhdr
608     elif tflag:
609         hdr = txhdr if xflag else thdr
610     else:  # Even if dflag is False, it's the default if none set
611         dflag = True
612         hdr = dxhdr if xflag else dhdr
613
614     if desired_cols:
615         hdr = desired_cols.split(",")
616
617         invalid = []
618         incompat = []
619         for ele in hdr:
620             if ele not in cols:
621                 invalid.append(ele)
622             elif ((bflag and bincompat and ele in bincompat) or
623                   (dflag and dincompat and ele in dincompat) or
624                   (tflag and tincompat and ele in tincompat)):
625                     incompat.append(ele)
626
627         if len(invalid) > 0:
628             sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
629             usage()
630
631         if len(incompat) > 0:
632             sys.stderr.write("Incompatible field specified! -- %s\n" %
633                              incompat)
634             usage()
635
636     if ofile:
637         try:
638             tmp = open(ofile, "w")
639             sys.stdout = tmp
640
641         except IOError:
642             sys.stderr.write("Cannot open %s for writing\n" % ofile)
643             sys.exit(1)
644
645     if not ifile:
646         ifile = '/proc/spl/kstat/zfs/dbufs'
647
648     if ifile is not "-":
649         try:
650             tmp = open(ifile, "r")
651             sys.stdin = tmp
652         except IOError:
653             sys.stderr.write("Cannot open %s for reading\n" % ifile)
654             sys.exit(1)
655
656     if bflag:
657         buffers_print_all(sys.stdin, filters, nflag)
658
659     if dflag:
660         print_dict(dnodes_build_dict(sys.stdin), filters, nflag)
661
662     if tflag:
663         print_dict(types_build_dict(sys.stdin), filters, nflag)
664
665
666 if __name__ == '__main__':
667     main()