]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - cmd/splslab/splslab.py
Add a script to display SPL slab cache statistics
[FreeBSD/FreeBSD.git] / cmd / splslab / splslab.py
1 #!/usr/bin/python
2
3 import sys
4 import time
5 import getopt
6 import re
7 import signal
8 from collections import defaultdict
9
10 class Stat:
11     # flag definitions based on the kmem.h
12     NOTOUCH = 1
13     NODEBUG = 2
14     KMEM = 32
15     VMEM = 64
16     SLAB = 128
17     OFFSLAB = 256
18     NOEMERGENCY = 512
19     DEADLOCKED = 16384
20     GROWING = 32768
21     REAPING = 65536
22     DESTROY = 131072
23
24     fdefs = {
25         NOTOUCH : "NTCH",
26         NODEBUG : "NDBG", 
27         KMEM : "KMEM",
28         VMEM : "VMEM",
29         SLAB : "SLAB",
30         OFFSLAB : "OFSL",
31         NOEMERGENCY : "NEMG",
32         DEADLOCKED : "DDLK",
33         GROWING : "GROW",
34         REAPING : "REAP",
35         DESTROY : "DSTR"
36         }
37
38     def __init__(self, name, flags, size, alloc, slabsize, objsize):
39         self._name = name
40         self._flags = self.f2str(flags)
41         self._size = size
42         self._alloc = alloc
43         self._slabsize = slabsize
44         self._objsize = objsize
45
46     def f2str(self, flags):
47         fstring = ''
48         for k in Stat.fdefs.keys():
49             if flags & k:
50                 fstring = fstring + Stat.fdefs[k] + '|'
51
52         fstring = fstring[:-1]
53         return fstring
54
55 class CumulativeStat:
56     def __init__(self, skey="a"):
57         self._size = 0
58         self._alloc = 0
59         self._pct = 0
60         self._skey = skey
61         self._regexp = \
62             re.compile('(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+');
63         self._stats = defaultdict(list)
64
65     # Add another stat to the dictionary and re-calculate the totals
66     def add(self, s):
67         key = 0
68         if self._skey == "a":
69             key = s._alloc
70         else:
71             key = s._size
72         self._stats[key].append(s)
73         self._size = self._size + s._size
74         self._alloc = self._alloc + s._alloc
75         if self._size:
76             self._pct = self._alloc * 100 / self._size
77         else:
78             self._pct = 0
79
80     # Parse the slab info in the procfs
81     # Calculate cumulative stats
82     def slab_update(self):
83         k = [line.strip() for line in open('/proc/spl/kmem/slab')]
84
85         if not k:
86             sys.stderr.write("No SPL slab stats found\n")
87             sys.exit(1)
88
89         del k[0:2]
90
91         for s in k:
92             if not s:
93                 continue
94             m = self._regexp.match(s)
95             if m:
96                 self.add(Stat(m.group(1), int(m.group(2),16), int(m.group(3)),
97                             int(m.group(4)), int(m.group(5)), int(m.group(6))))
98             else:
99                 sys.stderr.write("Error: unexpected input format\n" % s)
100                 exit(-1)
101
102     def show_header(self):
103         sys.stdout.write("\n%25s %20s %15s %15s %15s %15s\n\n" % \
104             ("cache name", "flags", "size", "alloc", "slabsize", "objsize"))
105
106     # Show up to the number of 'rows' of output sorted in descending order
107     # by the key specified earlier; if rows == 0, all rows are shown
108     def show(self, rows):
109         self.show_header()
110         i = 1
111         done = False
112         for k in reversed(sorted(self._stats.keys())):
113             for s in self._stats[k]:
114                 sys.stdout.write("%25s %20s %15d %15d %15d %15d\n" % \
115                                      (s._name, s._flags, s._size, s._alloc, \
116                                           s._slabsize, s._objsize))
117                 i = i + 1
118                 if rows != 0 and i > rows:
119                     done = True
120                     break
121             if done:
122                 break
123         sys.stdout.write("%25s %36d %15d (%d%%)\n\n" % \
124             ("Totals:", self._size, self._alloc, self._pct))
125
126 def usage():
127     cmd = "Usage: splslab.py [-n|--num-rows] number [-s|--sort-by] " + \
128         "[interval] [count]";
129     sys.stderr.write("%s\n" % cmd)
130     sys.stderr.write("\t-h : print help\n")
131     sys.stderr.write("\t-n : --num-rows N : limit output to N top " +
132                      "largest slabs (default: all)\n")
133     sys.stderr.write("\t-s : --sort-by key : sort output in descending " +
134                      "order by total size (s)\n\t\tor allocated size (a) " +
135                      "(default: a)\n")
136     sys.stderr.write("\tinterval : repeat every interval seconds\n")
137     sys.stderr.write("\tcount : output statistics count times and exit\n")
138     
139
140 def main():
141
142     rows = 0
143     count = 0
144     skey = "a"
145     interval = 1
146
147     signal.signal(signal.SIGINT, signal.SIG_DFL)
148
149     try:
150         opts, args = getopt.getopt(
151             sys.argv[1:],
152             "n:s:h",
153             [
154                 "num-rows",
155                 "sort-by",
156                 "help"
157             ]
158         )
159     except getopt.error as e:
160         sys.stderr.write("Error: %s\n" % e.msg)
161         usage()
162         exit(-1)
163
164     i = 1
165     for opt, arg in opts:
166         if opt in ('-n', '--num-rows'):
167             rows = int(arg)
168             i = i + 2
169         elif opt in ('-s', '--sort-by'):
170             if arg != "s" and arg != "a":
171                 sys.stderr.write("Error: invalid sorting key \"%s\"\n" % arg)
172                 usage()
173                 exit(-1)
174             skey = arg
175             i = i + 2
176         elif opt in ('-h', '--help'):
177             usage()
178             exit(0)
179         else:
180             break
181
182     args = sys.argv[i:]
183
184     interval = int(args[0]) if len(args) else interval
185     count = int(args[1]) if len(args) > 1 else count
186
187     i = 0
188     while True:
189         cs = CumulativeStat(skey)
190         cs.slab_update()
191         cs.show(rows)
192
193         i = i + 1
194         if count and i >= count:
195             break
196
197         time.sleep(interval)
198
199     return 0
200
201 if __name__ == '__main__':
202     main()