|
| 1 | +#!/usr/bin/env drgn |
| 2 | +# |
| 3 | +# Copyright (C) 2023 Tejun Heo <[email protected]> |
| 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 POOL_ID... |
| 40 | +
|
| 41 | + NAME name of the workqueue |
| 42 | + TYPE percpu, unbound or ordered |
| 43 | + POOL_ID worker pool ID associated with each possible CPU |
| 44 | +""" |
| 45 | + |
| 46 | +import sys |
| 47 | + |
| 48 | +import drgn |
| 49 | +from drgn.helpers.linux.list import list_for_each_entry,list_empty |
| 50 | +from drgn.helpers.linux.percpu import per_cpu_ptr |
| 51 | +from drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu |
| 52 | +from drgn.helpers.linux.idr import idr_for_each |
| 53 | + |
| 54 | +import argparse |
| 55 | +parser = argparse.ArgumentParser(description=desc, |
| 56 | + formatter_class=argparse.RawTextHelpFormatter) |
| 57 | +args = parser.parse_args() |
| 58 | + |
| 59 | +def err(s): |
| 60 | + print(s, file=sys.stderr, flush=True) |
| 61 | + sys.exit(1) |
| 62 | + |
| 63 | +def cpumask_str(cpumask): |
| 64 | + output = "" |
| 65 | + base = 0 |
| 66 | + v = 0 |
| 67 | + for cpu in for_each_cpu(cpumask[0]): |
| 68 | + while cpu - base >= 32: |
| 69 | + output += f'{hex(v)} ' |
| 70 | + base += 32 |
| 71 | + v = 0 |
| 72 | + v |= 1 << (cpu - base) |
| 73 | + if v > 0: |
| 74 | + output += f'{v:08x}' |
| 75 | + return output.strip() |
| 76 | + |
| 77 | +worker_pool_idr = prog['worker_pool_idr'] |
| 78 | +workqueues = prog['workqueues'] |
| 79 | +wq_unbound_cpumask = prog['wq_unbound_cpumask'] |
| 80 | +wq_pod_types = prog['wq_pod_types'] |
| 81 | + |
| 82 | +WQ_UNBOUND = prog['WQ_UNBOUND'] |
| 83 | +WQ_ORDERED = prog['__WQ_ORDERED'] |
| 84 | +WQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM'] |
| 85 | + |
| 86 | +WQ_AFFN_NUMA = prog['WQ_AFFN_NUMA'] |
| 87 | +WQ_AFFN_SYSTEM = prog['WQ_AFFN_SYSTEM'] |
| 88 | + |
| 89 | +print('Affinity Scopes') |
| 90 | +print('===============') |
| 91 | + |
| 92 | +print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}') |
| 93 | + |
| 94 | +def print_pod_type(pt): |
| 95 | + print(f' nr_pods {pt.nr_pods.value_()}') |
| 96 | + |
| 97 | + print(' pod_cpus', end='') |
| 98 | + for pod in range(pt.nr_pods): |
| 99 | + print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='') |
| 100 | + print('') |
| 101 | + |
| 102 | + print(' pod_node', end='') |
| 103 | + for pod in range(pt.nr_pods): |
| 104 | + print(f' [{pod}]={pt.pod_node[pod].value_()}', end='') |
| 105 | + print('') |
| 106 | + |
| 107 | + print(f' cpu_pod ', end='') |
| 108 | + for cpu in for_each_possible_cpu(prog): |
| 109 | + print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='') |
| 110 | + print('') |
| 111 | + |
| 112 | +print('') |
| 113 | +print('NUMA') |
| 114 | +print_pod_type(wq_pod_types[WQ_AFFN_NUMA]) |
| 115 | +print('') |
| 116 | +print('SYSTEM') |
| 117 | +print_pod_type(wq_pod_types[WQ_AFFN_SYSTEM]) |
| 118 | + |
| 119 | +print('') |
| 120 | +print('Worker Pools') |
| 121 | +print('============') |
| 122 | + |
| 123 | +max_pool_id_len = 0 |
| 124 | +max_ref_len = 0 |
| 125 | +for pi, pool in idr_for_each(worker_pool_idr): |
| 126 | + pool = drgn.Object(prog, 'struct worker_pool', address=pool) |
| 127 | + max_pool_id_len = max(max_pool_id_len, len(f'{pi}')) |
| 128 | + max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}')) |
| 129 | + |
| 130 | +for pi, pool in idr_for_each(worker_pool_idr): |
| 131 | + pool = drgn.Object(prog, 'struct worker_pool', address=pool) |
| 132 | + print(f'pool[{pi:0{max_pool_id_len}}] ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='') |
| 133 | + print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='') |
| 134 | + if pool.cpu >= 0: |
| 135 | + print(f'cpu={pool.cpu.value_():3}', end='') |
| 136 | + else: |
| 137 | + print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='') |
| 138 | + print('') |
| 139 | + |
| 140 | +print('') |
| 141 | +print('Workqueue CPU -> pool') |
| 142 | +print('=====================') |
| 143 | + |
| 144 | +print('[ workqueue \ CPU ', end='') |
| 145 | +for cpu in for_each_possible_cpu(prog): |
| 146 | + print(f' {cpu:{max_pool_id_len}}', end='') |
| 147 | +print(' dfl]') |
| 148 | + |
| 149 | +for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'): |
| 150 | + print(f'{wq.name.string_().decode()[-24:]:24}', end='') |
| 151 | + if wq.flags & WQ_UNBOUND: |
| 152 | + if wq.flags & WQ_ORDERED: |
| 153 | + print(' ordered', end='') |
| 154 | + else: |
| 155 | + print(' unbound', end='') |
| 156 | + else: |
| 157 | + print(' percpu ', end='') |
| 158 | + |
| 159 | + for cpu in for_each_possible_cpu(prog): |
| 160 | + pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_() |
| 161 | + field_len = max(len(str(cpu)), max_pool_id_len) |
| 162 | + print(f' {pool_id:{field_len}}', end='') |
| 163 | + |
| 164 | + if wq.flags & WQ_UNBOUND: |
| 165 | + print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='') |
| 166 | + print('') |
0 commit comments