17f7dc377STejun Heo#!/usr/bin/env drgn 27f7dc377STejun Heo# 37f7dc377STejun Heo# Copyright (C) 2023 Tejun Heo <[email protected]> 47f7dc377STejun Heo# Copyright (C) 2023 Meta Platforms, Inc. and affiliates. 57f7dc377STejun Heo 67f7dc377STejun Heodesc = """ 77f7dc377STejun HeoThis is a drgn script to show the current workqueue configuration. For more 87f7dc377STejun Heoinfo on drgn, visit https://github.com/osandov/drgn. 97f7dc377STejun Heo 107f7dc377STejun HeoAffinity Scopes 117f7dc377STejun Heo=============== 127f7dc377STejun Heo 137f7dc377STejun HeoShows the CPUs that can be used for unbound workqueues and how they will be 147f7dc377STejun Heogrouped by each available affinity type. For each type: 157f7dc377STejun Heo 167f7dc377STejun Heo nr_pods number of CPU pods in the affinity type 177f7dc377STejun Heo pod_cpus CPUs in each pod 187f7dc377STejun Heo pod_node NUMA node for memory allocation for each pod 197f7dc377STejun Heo cpu_pod pod that each CPU is associated to 207f7dc377STejun Heo 217f7dc377STejun HeoWorker Pools 227f7dc377STejun Heo============ 237f7dc377STejun Heo 247f7dc377STejun HeoLists all worker pools indexed by their ID. For each pool: 257f7dc377STejun Heo 267f7dc377STejun Heo ref number of pool_workqueue's associated with this pool 277f7dc377STejun Heo nice nice value of the worker threads in the pool 287f7dc377STejun Heo idle number of idle workers 297f7dc377STejun Heo workers number of all workers 307f7dc377STejun Heo cpu CPU the pool is associated with (per-cpu pool) 317f7dc377STejun Heo cpus CPUs the workers in the pool can run on (unbound pool) 327f7dc377STejun Heo 337f7dc377STejun HeoWorkqueue CPU -> pool 347f7dc377STejun Heo===================== 357f7dc377STejun Heo 367f7dc377STejun HeoLists all workqueues along with their type and worker pool association. For 377f7dc377STejun Heoeach workqueue: 387f7dc377STejun Heo 398639ecebSTejun Heo NAME TYPE[,FLAGS] POOL_ID... 407f7dc377STejun Heo 417f7dc377STejun Heo NAME name of the workqueue 427f7dc377STejun Heo TYPE percpu, unbound or ordered 438639ecebSTejun Heo FLAGS S: strict affinity scope 447f7dc377STejun Heo POOL_ID worker pool ID associated with each possible CPU 457f7dc377STejun Heo""" 467f7dc377STejun Heo 477f7dc377STejun Heoimport sys 487f7dc377STejun Heo 497f7dc377STejun Heoimport drgn 507f7dc377STejun Heofrom drgn.helpers.linux.list import list_for_each_entry,list_empty 517f7dc377STejun Heofrom drgn.helpers.linux.percpu import per_cpu_ptr 527f7dc377STejun Heofrom drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu 5307daa99bSTejun Heofrom drgn.helpers.linux.nodemask import for_each_node 547f7dc377STejun Heofrom drgn.helpers.linux.idr import idr_for_each 557f7dc377STejun Heo 567f7dc377STejun Heoimport argparse 577f7dc377STejun Heoparser = argparse.ArgumentParser(description=desc, 587f7dc377STejun Heo formatter_class=argparse.RawTextHelpFormatter) 597f7dc377STejun Heoargs = parser.parse_args() 607f7dc377STejun Heo 617f7dc377STejun Heodef err(s): 627f7dc377STejun Heo print(s, file=sys.stderr, flush=True) 637f7dc377STejun Heo sys.exit(1) 647f7dc377STejun Heo 657f7dc377STejun Heodef cpumask_str(cpumask): 667f7dc377STejun Heo output = "" 677f7dc377STejun Heo base = 0 687f7dc377STejun Heo v = 0 697f7dc377STejun Heo for cpu in for_each_cpu(cpumask[0]): 707f7dc377STejun Heo while cpu - base >= 32: 717f7dc377STejun Heo output += f'{hex(v)} ' 727f7dc377STejun Heo base += 32 737f7dc377STejun Heo v = 0 747f7dc377STejun Heo v |= 1 << (cpu - base) 757f7dc377STejun Heo if v > 0: 767f7dc377STejun Heo output += f'{v:08x}' 777f7dc377STejun Heo return output.strip() 787f7dc377STejun Heo 79a6b48c83STejun Heowq_type_len = 9 80a6b48c83STejun Heo 81a6b48c83STejun Heodef wq_type_str(wq): 82*4cb1ef64STejun Heo if wq.flags & WQ_BH: 83*4cb1ef64STejun Heo return f'{"bh":{wq_type_len}}' 84*4cb1ef64STejun Heo elif wq.flags & WQ_UNBOUND: 85a6b48c83STejun Heo if wq.flags & WQ_ORDERED: 86a6b48c83STejun Heo return f'{"ordered":{wq_type_len}}' 87a6b48c83STejun Heo else: 88a6b48c83STejun Heo if wq.unbound_attrs.affn_strict: 89a6b48c83STejun Heo return f'{"unbound,S":{wq_type_len}}' 90a6b48c83STejun Heo else: 91a6b48c83STejun Heo return f'{"unbound":{wq_type_len}}' 92a6b48c83STejun Heo else: 93a6b48c83STejun Heo return f'{"percpu":{wq_type_len}}' 94a6b48c83STejun Heo 957f7dc377STejun Heoworker_pool_idr = prog['worker_pool_idr'] 967f7dc377STejun Heoworkqueues = prog['workqueues'] 977f7dc377STejun Heowq_unbound_cpumask = prog['wq_unbound_cpumask'] 987f7dc377STejun Heowq_pod_types = prog['wq_pod_types'] 9963c5484eSTejun Heowq_affn_dfl = prog['wq_affn_dfl'] 10063c5484eSTejun Heowq_affn_names = prog['wq_affn_names'] 1017f7dc377STejun Heo 102*4cb1ef64STejun HeoWQ_BH = prog['WQ_BH'] 1037f7dc377STejun HeoWQ_UNBOUND = prog['WQ_UNBOUND'] 1047f7dc377STejun HeoWQ_ORDERED = prog['__WQ_ORDERED'] 1057f7dc377STejun HeoWQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM'] 1067f7dc377STejun Heo 10763c5484eSTejun HeoWQ_AFFN_CPU = prog['WQ_AFFN_CPU'] 10863c5484eSTejun HeoWQ_AFFN_SMT = prog['WQ_AFFN_SMT'] 10963c5484eSTejun HeoWQ_AFFN_CACHE = prog['WQ_AFFN_CACHE'] 1107f7dc377STejun HeoWQ_AFFN_NUMA = prog['WQ_AFFN_NUMA'] 1117f7dc377STejun HeoWQ_AFFN_SYSTEM = prog['WQ_AFFN_SYSTEM'] 1127f7dc377STejun Heo 113*4cb1ef64STejun HeoPOOL_BH = prog['POOL_BH'] 114*4cb1ef64STejun Heo 115a6b48c83STejun HeoWQ_NAME_LEN = prog['WQ_NAME_LEN'].value_() 116a6b48c83STejun Heocpumask_str_len = len(cpumask_str(wq_unbound_cpumask)) 117a6b48c83STejun Heo 1187f7dc377STejun Heoprint('Affinity Scopes') 1197f7dc377STejun Heoprint('===============') 1207f7dc377STejun Heo 1217f7dc377STejun Heoprint(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}') 1227f7dc377STejun Heo 1237f7dc377STejun Heodef print_pod_type(pt): 1247f7dc377STejun Heo print(f' nr_pods {pt.nr_pods.value_()}') 1257f7dc377STejun Heo 1267f7dc377STejun Heo print(' pod_cpus', end='') 1277f7dc377STejun Heo for pod in range(pt.nr_pods): 1287f7dc377STejun Heo print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='') 1297f7dc377STejun Heo print('') 1307f7dc377STejun Heo 1317f7dc377STejun Heo print(' pod_node', end='') 1327f7dc377STejun Heo for pod in range(pt.nr_pods): 1337f7dc377STejun Heo print(f' [{pod}]={pt.pod_node[pod].value_()}', end='') 1347f7dc377STejun Heo print('') 1357f7dc377STejun Heo 1367f7dc377STejun Heo print(f' cpu_pod ', end='') 1377f7dc377STejun Heo for cpu in for_each_possible_cpu(prog): 1387f7dc377STejun Heo print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='') 1397f7dc377STejun Heo print('') 1407f7dc377STejun Heo 14163c5484eSTejun Heofor affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]: 1427f7dc377STejun Heo print('') 14363c5484eSTejun Heo print(f'{wq_affn_names[affn].string_().decode().upper()}{" (default)" if affn == wq_affn_dfl else ""}') 14463c5484eSTejun Heo print_pod_type(wq_pod_types[affn]) 1457f7dc377STejun Heo 1467f7dc377STejun Heoprint('') 1477f7dc377STejun Heoprint('Worker Pools') 1487f7dc377STejun Heoprint('============') 1497f7dc377STejun Heo 1507f7dc377STejun Heomax_pool_id_len = 0 1517f7dc377STejun Heomax_ref_len = 0 1527f7dc377STejun Heofor pi, pool in idr_for_each(worker_pool_idr): 1537f7dc377STejun Heo pool = drgn.Object(prog, 'struct worker_pool', address=pool) 1547f7dc377STejun Heo max_pool_id_len = max(max_pool_id_len, len(f'{pi}')) 1557f7dc377STejun Heo max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}')) 1567f7dc377STejun Heo 1577f7dc377STejun Heofor pi, pool in idr_for_each(worker_pool_idr): 1587f7dc377STejun Heo pool = drgn.Object(prog, 'struct worker_pool', address=pool) 159*4cb1ef64STejun Heo 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='') 1607f7dc377STejun Heo print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='') 1617f7dc377STejun Heo if pool.cpu >= 0: 1627f7dc377STejun Heo print(f'cpu={pool.cpu.value_():3}', end='') 163*4cb1ef64STejun Heo if pool.flags & POOL_BH: 164*4cb1ef64STejun Heo print(' bh', end='') 1657f7dc377STejun Heo else: 1667f7dc377STejun Heo print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='') 1678639ecebSTejun Heo print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='') 1688639ecebSTejun Heo if pool.attrs.affn_strict: 1698639ecebSTejun Heo print(' strict', end='') 1707f7dc377STejun Heo print('') 1717f7dc377STejun Heo 1727f7dc377STejun Heoprint('') 1737f7dc377STejun Heoprint('Workqueue CPU -> pool') 1747f7dc377STejun Heoprint('=====================') 1757f7dc377STejun Heo 176a6b48c83STejun Heoprint(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"type CPU":{wq_type_len}}', end='') 1777f7dc377STejun Heofor cpu in for_each_possible_cpu(prog): 1787f7dc377STejun Heo print(f' {cpu:{max_pool_id_len}}', end='') 1797f7dc377STejun Heoprint(' dfl]') 1807f7dc377STejun Heo 1817f7dc377STejun Heofor wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'): 182a6b48c83STejun Heo print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} {wq_type_str(wq):10}', end='') 1837f7dc377STejun Heo 1847f7dc377STejun Heo for cpu in for_each_possible_cpu(prog): 1857f7dc377STejun Heo pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_() 1867f7dc377STejun Heo field_len = max(len(str(cpu)), max_pool_id_len) 1877f7dc377STejun Heo print(f' {pool_id:{field_len}}', end='') 1887f7dc377STejun Heo 1897f7dc377STejun Heo if wq.flags & WQ_UNBOUND: 1907f7dc377STejun Heo print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='') 1917f7dc377STejun Heo print('') 192ab5e5b99SJuri Lelli 193ab5e5b99SJuri Lelliprint('') 194ab5e5b99SJuri Lelliprint('Workqueue -> rescuer') 195a6b48c83STejun Heoprint('====================') 196a6b48c83STejun Heo 197a6b48c83STejun Heoucpus_len = max(cpumask_str_len, len("unbound_cpus")) 198a6b48c83STejun Heorcpus_len = max(cpumask_str_len, len("rescuer_cpus")) 199a6b48c83STejun Heo 200a6b48c83STejun Heoprint(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ {"unbound_cpus":{ucpus_len}} pid {"rescuer_cpus":{rcpus_len}} ]') 201ab5e5b99SJuri Lelli 202ab5e5b99SJuri Lellifor wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'): 203a6b48c83STejun Heo if not (wq.flags & WQ_MEM_RECLAIM): 204a6b48c83STejun Heo continue 205ab5e5b99SJuri Lelli 206a6b48c83STejun Heo print(f'{wq.name.string_().decode():{WQ_NAME_LEN}}', end='') 207a6b48c83STejun Heo if wq.unbound_attrs.value_() != 0: 208a6b48c83STejun Heo print(f' {cpumask_str(wq.unbound_attrs.cpumask):{ucpus_len}}', end='') 209a6b48c83STejun Heo else: 210a6b48c83STejun Heo print(f' {"":{ucpus_len}}', end='') 211a6b48c83STejun Heo 212a6b48c83STejun Heo print(f' {wq.rescuer.task.pid.value_():6}', end='') 213a6b48c83STejun Heo print(f' {cpumask_str(wq.rescuer.task.cpus_ptr):{rcpus_len}}', end='') 214ab5e5b99SJuri Lelli print('') 21507daa99bSTejun Heo 21607daa99bSTejun Heoprint('') 21707daa99bSTejun Heoprint('Unbound workqueue -> node_nr/max_active') 21807daa99bSTejun Heoprint('=======================================') 21907daa99bSTejun Heo 22007daa99bSTejun Heoif 'node_to_cpumask_map' in prog: 22107daa99bSTejun Heo __cpu_online_mask = prog['__cpu_online_mask'] 22207daa99bSTejun Heo node_to_cpumask_map = prog['node_to_cpumask_map'] 22307daa99bSTejun Heo nr_node_ids = prog['nr_node_ids'].value_() 22407daa99bSTejun Heo 22507daa99bSTejun Heo print(f'online_cpus={cpumask_str(__cpu_online_mask.address_of_())}') 22607daa99bSTejun Heo for node in for_each_node(): 22707daa99bSTejun Heo print(f'NODE[{node:02}]={cpumask_str(node_to_cpumask_map[node])}') 22807daa99bSTejun Heo print('') 22907daa99bSTejun Heo 23007daa99bSTejun Heo print(f'[{"workqueue":^{WQ_NAME_LEN-2}}\\ min max', end='') 23107daa99bSTejun Heo first = True 23207daa99bSTejun Heo for node in for_each_node(): 23307daa99bSTejun Heo if first: 23407daa99bSTejun Heo print(f' NODE {node}', end='') 23507daa99bSTejun Heo first = False 23607daa99bSTejun Heo else: 23707daa99bSTejun Heo print(f' {node:7}', end='') 23807daa99bSTejun Heo print(f' {"dfl":>7} ]') 23907daa99bSTejun Heo print('') 24007daa99bSTejun Heo 24107daa99bSTejun Heo for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'): 24207daa99bSTejun Heo if not (wq.flags & WQ_UNBOUND): 24307daa99bSTejun Heo continue 24407daa99bSTejun Heo 24507daa99bSTejun Heo print(f'{wq.name.string_().decode():{WQ_NAME_LEN}} ', end='') 24607daa99bSTejun Heo print(f'{wq.min_active.value_():3} {wq.max_active.value_():3}', end='') 24707daa99bSTejun Heo for node in for_each_node(): 24807daa99bSTejun Heo nna = wq.node_nr_active[node] 24907daa99bSTejun Heo print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}', end='') 25007daa99bSTejun Heo nna = wq.node_nr_active[nr_node_ids] 25107daa99bSTejun Heo print(f' {nna.nr.counter.value_():3}/{nna.max.value_():3}') 25207daa99bSTejun Heoelse: 25307daa99bSTejun Heo printf(f'node_to_cpumask_map not present, is NUMA enabled?') 254