~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/writeback/wb_monitor.py

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/usr/bin/env drgn
  2 #
  3 # Copyright (C) 2024 Kemeng Shi <shikemeng@huaweicloud.com>
  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()

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php