Merge tag 'input-for-v6.6-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor...
[linux-block.git] / tools / workqueue / wq_dump.py
CommitLineData
7f7dc377
TH
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
6desc = """
7This is a drgn script to show the current workqueue configuration. For more
8info on drgn, visit https://github.com/osandov/drgn.
9
10Affinity Scopes
11===============
12
13Shows the CPUs that can be used for unbound workqueues and how they will be
14grouped 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
21Worker Pools
22============
23
24Lists 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
33Workqueue CPU -> pool
34=====================
35
36Lists all workqueues along with their type and worker pool association. For
37each workqueue:
38
8639eceb 39 NAME TYPE[,FLAGS] POOL_ID...
7f7dc377
TH
40
41 NAME name of the workqueue
42 TYPE percpu, unbound or ordered
8639eceb 43 FLAGS S: strict affinity scope
7f7dc377
TH
44 POOL_ID worker pool ID associated with each possible CPU
45"""
46
47import sys
48
49import drgn
50from drgn.helpers.linux.list import list_for_each_entry,list_empty
51from drgn.helpers.linux.percpu import per_cpu_ptr
52from drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu
53from drgn.helpers.linux.idr import idr_for_each
54
55import argparse
56parser = argparse.ArgumentParser(description=desc,
57 formatter_class=argparse.RawTextHelpFormatter)
58args = parser.parse_args()
59
60def err(s):
61 print(s, file=sys.stderr, flush=True)
62 sys.exit(1)
63
64def 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
78worker_pool_idr = prog['worker_pool_idr']
79workqueues = prog['workqueues']
80wq_unbound_cpumask = prog['wq_unbound_cpumask']
81wq_pod_types = prog['wq_pod_types']
63c5484e
TH
82wq_affn_dfl = prog['wq_affn_dfl']
83wq_affn_names = prog['wq_affn_names']
7f7dc377
TH
84
85WQ_UNBOUND = prog['WQ_UNBOUND']
86WQ_ORDERED = prog['__WQ_ORDERED']
87WQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM']
88
63c5484e
TH
89WQ_AFFN_CPU = prog['WQ_AFFN_CPU']
90WQ_AFFN_SMT = prog['WQ_AFFN_SMT']
91WQ_AFFN_CACHE = prog['WQ_AFFN_CACHE']
7f7dc377
TH
92WQ_AFFN_NUMA = prog['WQ_AFFN_NUMA']
93WQ_AFFN_SYSTEM = prog['WQ_AFFN_SYSTEM']
94
95print('Affinity Scopes')
96print('===============')
97
98print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}')
99
100def 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
63c5484e
TH
118for 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])
7f7dc377
TH
122
123print('')
124print('Worker Pools')
125print('============')
126
127max_pool_id_len = 0
128max_ref_len = 0
129for 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
134for 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='')
8639eceb
TH
142 print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='')
143 if pool.attrs.affn_strict:
144 print(' strict', end='')
7f7dc377
TH
145 print('')
146
147print('')
148print('Workqueue CPU -> pool')
149print('=====================')
150
8639eceb 151print('[ workqueue \ type CPU', end='')
7f7dc377
TH
152for cpu in for_each_possible_cpu(prog):
153 print(f' {cpu:{max_pool_id_len}}', end='')
154print(' dfl]')
155
156for 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:
8639eceb 160 print(' ordered ', end='')
7f7dc377
TH
161 else:
162 print(' unbound', end='')
8639eceb
TH
163 if wq.unbound_attrs.affn_strict:
164 print(',S ', end='')
165 else:
166 print(' ', end='')
7f7dc377 167 else:
8639eceb 168 print(' percpu ', end='')
7f7dc377
TH
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('')