]> Git Repo - J-linux.git/blob - tools/writeback/wb_monitor.py
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / writeback / wb_monitor.py
1 #!/usr/bin/env drgn
2 #
3 # Copyright (C) 2024 Kemeng Shi <[email protected]>
4 # Copyright (C) 2024 Huawei Inc
5
6 desc = """
7 This is a drgn script based on wq_monitor.py to monitor writeback info on
8 backing dev. For more info on drgn, visit https://github.com/osandov/drgn.
9
10   writeback(kB)     Amount of dirty pages are currently being written back to
11                     disk.
12
13   reclaimable(kB)   Amount of pages are currently reclaimable.
14
15   dirtied(kB)       Amount of pages have been dirtied.
16
17   wrttien(kB)       Amount of dirty pages have been written back to disk.
18
19   avg_wb(kBps)      Smoothly estimated write bandwidth of writing dirty pages
20                     back to disk.
21 """
22
23 import signal
24 import re
25 import time
26 import json
27
28 import drgn
29 from drgn.helpers.linux.list import list_for_each_entry
30
31 import argparse
32 parser = argparse.ArgumentParser(description=desc,
33                                  formatter_class=argparse.RawTextHelpFormatter)
34 parser.add_argument('bdi', metavar='REGEX', nargs='*',
35                     help='Target backing device name patterns (all if empty)')
36 parser.add_argument('-i', '--interval', metavar='SECS', type=float, default=1,
37                     help='Monitoring interval (0 to print once and exit)')
38 parser.add_argument('-j', '--json', action='store_true',
39                     help='Output in json')
40 parser.add_argument('-c', '--cgroup', action='store_true',
41                     help='show writeback of bdi in cgroup')
42 args = parser.parse_args()
43
44 bdi_list                = prog['bdi_list']
45
46 WB_RECLAIMABLE          = prog['WB_RECLAIMABLE']
47 WB_WRITEBACK            = prog['WB_WRITEBACK']
48 WB_DIRTIED              = prog['WB_DIRTIED']
49 WB_WRITTEN              = prog['WB_WRITTEN']
50 NR_WB_STAT_ITEMS        = prog['NR_WB_STAT_ITEMS']
51
52 PAGE_SHIFT              = prog['PAGE_SHIFT']
53
54 def K(x):
55     return x << (PAGE_SHIFT - 10)
56
57 class Stats:
58     def dict(self, now):
59         return { 'timestamp'            : now,
60                  'name'                 : self.name,
61                  'writeback'            : self.stats[WB_WRITEBACK],
62                  'reclaimable'          : self.stats[WB_RECLAIMABLE],
63                  'dirtied'              : self.stats[WB_DIRTIED],
64                  'written'              : self.stats[WB_WRITTEN],
65                  'avg_wb'               : self.avg_bw, }
66
67     def table_header_str():
68         return f'{"":>16} {"writeback":>10} {"reclaimable":>12} ' \
69                 f'{"dirtied":>9} {"written":>9} {"avg_bw":>9}'
70
71     def table_row_str(self):
72         out = f'{self.name[-16:]:16} ' \
73               f'{self.stats[WB_WRITEBACK]:10} ' \
74               f'{self.stats[WB_RECLAIMABLE]:12} ' \
75               f'{self.stats[WB_DIRTIED]:9} ' \
76               f'{self.stats[WB_WRITTEN]:9} ' \
77               f'{self.avg_bw:9} '
78         return out
79
80     def show_header():
81         if Stats.table_fmt:
82             print()
83             print(Stats.table_header_str())
84
85     def show_stats(self):
86         if Stats.table_fmt:
87             print(self.table_row_str())
88         else:
89             print(self.dict(Stats.now))
90
91 class WbStats(Stats):
92     def __init__(self, wb):
93         bdi_name = wb.bdi.dev_name.string_().decode()
94         # avoid to use bdi.wb.memcg_css which is only defined when
95         # CONFIG_CGROUP_WRITEBACK is enabled
96         if wb == wb.bdi.wb.address_of_():
97             ino = "1"
98         else:
99             ino = str(wb.memcg_css.cgroup.kn.id.value_())
100         self.name = bdi_name + '_' + ino
101
102         self.stats = [0] * NR_WB_STAT_ITEMS
103         for i in range(NR_WB_STAT_ITEMS):
104             if wb.stat[i].count >= 0:
105                 self.stats[i] = int(K(wb.stat[i].count))
106             else:
107                 self.stats[i] = 0
108
109         self.avg_bw = int(K(wb.avg_write_bandwidth))
110
111 class BdiStats(Stats):
112     def __init__(self, bdi):
113         self.name = bdi.dev_name.string_().decode()
114         self.stats = [0] * NR_WB_STAT_ITEMS
115         self.avg_bw = 0
116
117     def collectStats(self, wb_stats):
118         for i in range(NR_WB_STAT_ITEMS):
119             self.stats[i] += wb_stats.stats[i]
120
121         self.avg_bw += wb_stats.avg_bw
122
123 exit_req = False
124
125 def sigint_handler(signr, frame):
126     global exit_req
127     exit_req = True
128
129 def main():
130     # handle args
131     Stats.table_fmt = not args.json
132     interval = args.interval
133     cgroup = args.cgroup
134
135     re_str = None
136     if args.bdi:
137         for r in args.bdi:
138             if re_str is None:
139                 re_str = r
140             else:
141                 re_str += '|' + r
142
143     filter_re = re.compile(re_str) if re_str else None
144
145     # monitoring loop
146     signal.signal(signal.SIGINT, sigint_handler)
147
148     while not exit_req:
149         Stats.now = time.time()
150
151         Stats.show_header()
152         for bdi in list_for_each_entry('struct backing_dev_info', bdi_list.address_of_(), 'bdi_list'):
153             bdi_stats = BdiStats(bdi)
154             if filter_re and not filter_re.search(bdi_stats.name):
155                 continue
156
157             for wb in list_for_each_entry('struct bdi_writeback', bdi.wb_list.address_of_(), 'bdi_node'):
158                 wb_stats = WbStats(wb)
159                 bdi_stats.collectStats(wb_stats)
160                 if cgroup:
161                     wb_stats.show_stats()
162
163             bdi_stats.show_stats()
164             if cgroup and Stats.table_fmt:
165                 print()
166
167         if interval == 0:
168             break
169         time.sleep(interval)
170
171 if __name__ == "__main__":
172     main()
This page took 0.036661 seconds and 4 git commands to generate.