3 # Copyright (C) 2023 Tejun Heo <tj@kernel.org>
4 # Copyright (C) 2023 Meta Platforms, Inc. and affiliates.
7 This is a drgn script to show the current workqueue configuration. For more
8 info on drgn, visit https://github.com/osandov/drgn.
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:
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
24 Lists all worker pools indexed by their ID. For each pool:
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)
36 Lists all workqueues along with their type and worker pool association. For
39 NAME TYPE[,FLAGS] POOL_ID...
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
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
56 parser = argparse.ArgumentParser(description=desc,
57 formatter_class=argparse.RawTextHelpFormatter)
58 args = parser.parse_args()
61 print(s, file=sys.stderr, flush=True)
64 def cpumask_str(cpumask):
68 for cpu in for_each_cpu(cpumask[0]):
69 while cpu - base >= 32:
70 output += f'{hex(v)} '
73 v |= 1 << (cpu - base)
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']
85 WQ_UNBOUND = prog['WQ_UNBOUND']
86 WQ_ORDERED = prog['__WQ_ORDERED']
87 WQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM']
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']
95 print('Affinity Scopes')
96 print('===============')
98 print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}')
100 def print_pod_type(pt):
101 print(f' nr_pods {pt.nr_pods.value_()}')
103 print(' pod_cpus', end='')
104 for pod in range(pt.nr_pods):
105 print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='')
108 print(' pod_node', end='')
109 for pod in range(pt.nr_pods):
110 print(f' [{pod}]={pt.pod_node[pod].value_()}', end='')
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='')
118 for affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]:
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])
124 print('Worker Pools')
125 print('============')
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_()}'))
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='')
139 print(f'cpu={pool.cpu.value_():3}', end='')
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='')
148 print('Workqueue CPU -> pool')
149 print('=====================')
151 print('[ workqueue \ type CPU', end='')
152 for cpu in for_each_possible_cpu(prog):
153 print(f' {cpu:{max_pool_id_len}}', end='')
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='')
162 print(' unbound', end='')
163 if wq.unbound_attrs.affn_strict:
168 print(' percpu ', end='')
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='')
175 if wq.flags & WQ_UNBOUND:
176 print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='')