Merge tag 'xtensa-20230905' of https://github.com/jcmvbkbc/linux-xtensa
[linux-2.6-microblaze.git] / tools / workqueue / wq_dump.py
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.idr import idr_for_each
54
55 import argparse
56 parser = argparse.ArgumentParser(description=desc,
57                                  formatter_class=argparse.RawTextHelpFormatter)
58 args = parser.parse_args()
59
60 def err(s):
61     print(s, file=sys.stderr, flush=True)
62     sys.exit(1)
63
64 def cpumask_str(cpumask):
65     output = ""
66     base = 0
67     v = 0
68     for cpu in for_each_cpu(cpumask[0]):
69         while cpu - base >= 32:
70             output += f'{hex(v)} '
71             base += 32
72             v = 0
73         v |= 1 << (cpu - base)
74     if v > 0:
75         output += f'{v:08x}'
76     return output.strip()
77
78 worker_pool_idr         = prog['worker_pool_idr']
79 workqueues              = prog['workqueues']
80 wq_unbound_cpumask      = prog['wq_unbound_cpumask']
81 wq_pod_types            = prog['wq_pod_types']
82 wq_affn_dfl             = prog['wq_affn_dfl']
83 wq_affn_names           = prog['wq_affn_names']
84
85 WQ_UNBOUND              = prog['WQ_UNBOUND']
86 WQ_ORDERED              = prog['__WQ_ORDERED']
87 WQ_MEM_RECLAIM          = prog['WQ_MEM_RECLAIM']
88
89 WQ_AFFN_CPU             = prog['WQ_AFFN_CPU']
90 WQ_AFFN_SMT             = prog['WQ_AFFN_SMT']
91 WQ_AFFN_CACHE           = prog['WQ_AFFN_CACHE']
92 WQ_AFFN_NUMA            = prog['WQ_AFFN_NUMA']
93 WQ_AFFN_SYSTEM          = prog['WQ_AFFN_SYSTEM']
94
95 print('Affinity Scopes')
96 print('===============')
97
98 print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}')
99
100 def print_pod_type(pt):
101     print(f'  nr_pods  {pt.nr_pods.value_()}')
102
103     print('  pod_cpus', end='')
104     for pod in range(pt.nr_pods):
105         print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='')
106     print('')
107
108     print('  pod_node', end='')
109     for pod in range(pt.nr_pods):
110         print(f' [{pod}]={pt.pod_node[pod].value_()}', end='')
111     print('')
112
113     print(f'  cpu_pod ', end='')
114     for cpu in for_each_possible_cpu(prog):
115         print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='')
116     print('')
117
118 for affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]:
119     print('')
120     print(f'{wq_affn_names[affn].string_().decode().upper()}{" (default)" if affn == wq_affn_dfl else ""}')
121     print_pod_type(wq_pod_types[affn])
122
123 print('')
124 print('Worker Pools')
125 print('============')
126
127 max_pool_id_len = 0
128 max_ref_len = 0
129 for pi, pool in idr_for_each(worker_pool_idr):
130     pool = drgn.Object(prog, 'struct worker_pool', address=pool)
131     max_pool_id_len = max(max_pool_id_len, len(f'{pi}'))
132     max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}'))
133
134 for pi, pool in idr_for_each(worker_pool_idr):
135     pool = drgn.Object(prog, 'struct worker_pool', address=pool)
136     print(f'pool[{pi:0{max_pool_id_len}}] ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='')
137     print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='')
138     if pool.cpu >= 0:
139         print(f'cpu={pool.cpu.value_():3}', end='')
140     else:
141         print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='')
142         print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='')
143         if pool.attrs.affn_strict:
144             print(' strict', end='')
145     print('')
146
147 print('')
148 print('Workqueue CPU -> pool')
149 print('=====================')
150
151 print('[    workqueue     \     type   CPU', end='')
152 for cpu in for_each_possible_cpu(prog):
153     print(f' {cpu:{max_pool_id_len}}', end='')
154 print(' dfl]')
155
156 for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
157     print(f'{wq.name.string_().decode()[-24:]:24}', end='')
158     if wq.flags & WQ_UNBOUND:
159         if wq.flags & WQ_ORDERED:
160             print(' ordered   ', end='')
161         else:
162             print(' unbound', end='')
163             if wq.unbound_attrs.affn_strict:
164                 print(',S ', end='')
165             else:
166                 print('   ', end='')
167     else:
168         print(' percpu    ', end='')
169
170     for cpu in for_each_possible_cpu(prog):
171         pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_()
172         field_len = max(len(str(cpu)), max_pool_id_len)
173         print(f' {pool_id:{field_len}}', end='')
174
175     if wq.flags & WQ_UNBOUND:
176         print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='')
177     print('')