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

TOMOYO Linux Cross Reference
Linux/tools/workqueue/wq_dump.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) 2023 Tejun Heo <tj@kernel.org>
  4 # Copyright (C) 2023 Meta Platforms, Inc. and affiliates.
  5 
  6 desc = """
  7 This is a drgn script to show the current workqueue configuration. For more
  8 info on drgn, visit https://github.com/osandov/drgn.
  9 
 10 Affinity Scopes
 11 ===============
 12 
 13 Shows the CPUs that can be used for unbound workqueues and how they will be
 14 grouped by each available affinity type. For each type:
 15 
 16   nr_pods   number of CPU pods in the affinity type
 17   pod_cpus  CPUs in each pod
 18   pod_node  NUMA node for memory allocation for each pod
 19   cpu_pod   pod that each CPU is associated to
 20 
 21 Worker Pools
 22 ============
 23 
 24 Lists all worker pools indexed by their ID. For each pool:
 25 
 26   ref       number of pool_workqueue's associated with this pool
 27   nice      nice value of the worker threads in the pool
 28   idle      number of idle workers
 29   workers   number of all workers
 30   cpu       CPU the pool is associated with (per-cpu pool)
 31   cpus      CPUs the workers in the pool can run on (unbound pool)
 32 
 33 Workqueue CPU -> pool
 34 =====================
 35 
 36 Lists all workqueues along with their type and worker pool association. For
 37 each workqueue:
 38 
 39   NAME TYPE[,FLAGS] POOL_ID...
 40 
 41   NAME      name of the workqueue
 42   TYPE      percpu, unbound or ordered
 43   FLAGS     S: strict affinity scope
 44   POOL_ID   worker pool ID associated with each possible CPU
 45 """
 46 
 47 import sys
 48 
 49 import drgn
 50 from drgn.helpers.linux.list import list_for_each_entry,list_empty
 51 from drgn.helpers.linux.percpu import per_cpu_ptr
 52 from drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu
 53 from drgn.helpers.linux.nodemask import for_each_node
 54 from drgn.helpers.linux.idr import idr_for_each
 55 
 56 import argparse
 57 parser = argparse.ArgumentParser(description=desc,
 58                                  formatter_class=argparse.RawTextHelpFormatter)
 59 args = parser.parse_args()
 60 
 61 def err(s):
 62     print(s, file=sys.stderr, flush=True)
 63     sys.exit(1)
 64 
 65 def cpumask_str(cpumask):
 66     output = ""
 67     base = 0
 68     v = 0
 69     for cpu in for_each_cpu(cpumask[0]):
 70         while cpu - base >= 32:
 71             output += f'{hex(v)} '
 72             base += 32
 73             v = 0
 74         v |= 1 << (cpu - base)
 75     if v > 0:
 76         output += f'{v:08x}'
 77     return output.strip()
 78 
 79 wq_type_len = 9
 80 
 81 def wq_type_str(wq):
 82     if wq.flags & WQ_BH:
 83         return f'{"bh":{wq_type_len}}'
 84     elif wq.flags & WQ_UNBOUND:
 85         if wq.flags & WQ_ORDERED:
 86             return f'{"ordered":{wq_type_len}}'
 87         else:
 88             if wq.unbound_attrs.affn_strict:
 89                 return f'{"unbound,S":{wq_type_len}}'
 90             else:
 91                 return f'{"unbound":{wq_type_len}}'
 92     else:
 93         return f'{"percpu":{wq_type_len}}'
 94 
 95 worker_pool_idr         = prog['worker_pool_idr']
 96 workqueues              = prog['workqueues']
 97 wq_unbound_cpumask      = prog['wq_unbound_cpumask']
 98 wq_pod_types            = prog['wq_pod_types']
 99 wq_affn_dfl             = prog['wq_affn_dfl']
100 wq_affn_names           = prog['wq_affn_names']
101 
102 WQ_BH                   = prog['WQ_BH']
103 WQ_UNBOUND              = prog['WQ_UNBOUND']
104 WQ_ORDERED              = prog['__WQ_ORDERED']
105 WQ_MEM_RECLAIM          = prog['WQ_MEM_RECLAIM']
106 
107 WQ_AFFN_CPU             = prog['WQ_AFFN_CPU']
108 WQ_AFFN_SMT             = prog['WQ_AFFN_SMT']
109 WQ_AFFN_CACHE           = prog['WQ_AFFN_CACHE']
110 WQ_AFFN_NUMA            = prog['WQ_AFFN_NUMA']
111 WQ_AFFN_SYSTEM          = prog['WQ_AFFN_SYSTEM']
112 
113 POOL_BH                 = prog['POOL_BH']
114 
115 WQ_NAME_LEN             = prog['WQ_NAME_LEN'].value_()
116 cpumask_str_len         = len(cpumask_str(wq_unbound_cpumask))
117 
118 print('Affinity Scopes')
119 print('===============')
120 
121 print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}')
122 
123 def print_pod_type(pt):
124     print(f'  nr_pods  {pt.nr_pods.value_()}')
125 
126     print('  pod_cpus', end='')
127     for pod in range(pt.nr_pods):
128         print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='')
129     print('')
130 
131     print('  pod_node', end='')
132     for pod in range(pt.nr_pods):
133         print(f' [{pod}]={pt.pod_node[pod].value_()}', end='')
134     print('')
135 
136     print(f'  cpu_pod ', end='')
137     for cpu in for_each_possible_cpu(prog):
138         print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='')
139     print('')
140 
141 for affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]:
142     print('')
143     print(f'{wq_affn_names[affn].string_().decode().upper()}{" (default)" if affn == wq_affn_dfl else ""}')
144     print_pod_type(wq_pod_types[affn])
145 
146 print('')
147 print('Worker Pools')
148 print('============')
149 
150 max_pool_id_len = 0
151 max_ref_len = 0
152 for pi, pool in idr_for_each(worker_pool_idr):
153     pool = drgn.Object(prog, 'struct worker_pool', address=pool)
154     max_pool_id_len = max(max_pool_id_len, len(f'{pi}'))
155     max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}'))
156 
157 for pi, pool in idr_for_each(worker_pool_idr):
158     pool = drgn.Object(prog, 'struct worker_pool', address=pool)
159     print(f'pool[{pi:0{max_pool_id_len}}] flags=0x{pool.flags.value_():02x} ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='')
160     print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='')
161     if pool.cpu >= 0:
162         print(f'cpu={pool.cpu.value_():3}', end='')
163         if pool.flags & POOL_BH:
164             print(' bh', end='')
165     else:
166         print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='')
167         print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='')
168         if pool.attrs.affn_strict:
169             print(' strict', end='')
170     print('')
171 
172 print('')
173 print('Workqueue CPU -> pool')
174 print('=====================')
175 
176 print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"type   CPU":{wq_type_len}}', end='')
177 for cpu in for_each_possible_cpu(prog):
178     print(f' {cpu:{max_pool_id_len}}', end='')
179 print(' dfl]')
180 
181 for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
182     print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} {wq_type_str(wq):10}', end='')
183 
184     for cpu in for_each_possible_cpu(prog):
185         pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_()
186         field_len = max(len(str(cpu)), max_pool_id_len)
187         print(f' {pool_id:{field_len}}', end='')
188 
189     if wq.flags & WQ_UNBOUND:
190         print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='')
191     print('')
192 
193 print('')
194 print('Workqueue -> rescuer')
195 print('====================')
196 
197 ucpus_len = max(cpumask_str_len, len("unbound_cpus"))
198 rcpus_len = max(cpumask_str_len, len("rescuer_cpus"))
199 
200 print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"unbound_cpus":{ucpus_len}}    pid {"rescuer_cpus":{rcpus_len}} ]')
201 
202 for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
203     if not (wq.flags & WQ_MEM_RECLAIM):
204         continue
205 
206     print(f'{wq.name.string_().decode():{WQ_NAME_LEN}}', end='')
207     if wq.unbound_attrs.value_() != 0:
208         print(f' {cpumask_str(wq.unbound_attrs.cpumask):{ucpus_len}}', end='')
209     else:
210         print(f' {"":{ucpus_len}}', end='')
211 
212     print(f' {wq.rescuer.task.pid.value_():6}', end='')
213     print(f' {cpumask_str(wq.rescuer.task.cpus_ptr):{rcpus_len}}', end='')
214     print('')
215 
216 print('')
217 print('Unbound workqueue -> node_nr/max_active')
218 print('=======================================')
219 
220 if 'node_to_cpumask_map' in prog:
221     __cpu_online_mask = prog['__cpu_online_mask']
222     node_to_cpumask_map = prog['node_to_cpumask_map']
223     nr_node_ids = prog['nr_node_ids'].value_()
224 
225     print(f'online_cpus={cpumask_str(__cpu_online_mask.address_of_())}')
226     for node in for_each_node():
227         print(f'NODE[{node:02}]={cpumask_str(node_to_cpumask_map[node])}')
228     print('')
229 
230     print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ min max', end='')
231     first = True
232     for node in for_each_node():
233         if first:
234             print(f'  NODE {node}', end='')
235             first = False
236         else:
237             print(f' {node:7}', end='')
238     print(f' {"dfl":>7} ]')
239     print('')
240 
241     for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
242         if not (wq.flags & WQ_UNBOUND):
243             continue
244 
245         print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} ', end='')
246         print(f'{wq.min_active.value_():3} {wq.max_active.value_():3}', end='')
247         for node in for_each_node():
248             nna = wq.node_nr_active[node]
249             print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}', end='')
250         nna = wq.node_nr_active[nr_node_ids]
251         print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}')
252 else:
253     printf(f'node_to_cpumask_map not present, is NUMA enabled?')

~ [ 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