162306a36Sopenharmony_ci#!/usr/bin/env drgn
262306a36Sopenharmony_ci#
362306a36Sopenharmony_ci# Copyright (C) 2023 Tejun Heo <tj@kernel.org>
462306a36Sopenharmony_ci# Copyright (C) 2023 Meta Platforms, Inc. and affiliates.
562306a36Sopenharmony_ci
662306a36Sopenharmony_cidesc = """
762306a36Sopenharmony_ciThis is a drgn script to show the current workqueue configuration. For more
862306a36Sopenharmony_ciinfo on drgn, visit https://github.com/osandov/drgn.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciAffinity Scopes
1162306a36Sopenharmony_ci===============
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciShows the CPUs that can be used for unbound workqueues and how they will be
1462306a36Sopenharmony_cigrouped by each available affinity type. For each type:
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci  nr_pods   number of CPU pods in the affinity type
1762306a36Sopenharmony_ci  pod_cpus  CPUs in each pod
1862306a36Sopenharmony_ci  pod_node  NUMA node for memory allocation for each pod
1962306a36Sopenharmony_ci  cpu_pod   pod that each CPU is associated to
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciWorker Pools
2262306a36Sopenharmony_ci============
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciLists all worker pools indexed by their ID. For each pool:
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci  ref       number of pool_workqueue's associated with this pool
2762306a36Sopenharmony_ci  nice      nice value of the worker threads in the pool
2862306a36Sopenharmony_ci  idle      number of idle workers
2962306a36Sopenharmony_ci  workers   number of all workers
3062306a36Sopenharmony_ci  cpu       CPU the pool is associated with (per-cpu pool)
3162306a36Sopenharmony_ci  cpus      CPUs the workers in the pool can run on (unbound pool)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciWorkqueue CPU -> pool
3462306a36Sopenharmony_ci=====================
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciLists all workqueues along with their type and worker pool association. For
3762306a36Sopenharmony_cieach workqueue:
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci  NAME TYPE[,FLAGS] POOL_ID...
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci  NAME      name of the workqueue
4262306a36Sopenharmony_ci  TYPE      percpu, unbound or ordered
4362306a36Sopenharmony_ci  FLAGS     S: strict affinity scope
4462306a36Sopenharmony_ci  POOL_ID   worker pool ID associated with each possible CPU
4562306a36Sopenharmony_ci"""
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciimport sys
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciimport drgn
5062306a36Sopenharmony_cifrom drgn.helpers.linux.list import list_for_each_entry,list_empty
5162306a36Sopenharmony_cifrom drgn.helpers.linux.percpu import per_cpu_ptr
5262306a36Sopenharmony_cifrom drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu
5362306a36Sopenharmony_cifrom drgn.helpers.linux.idr import idr_for_each
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciimport argparse
5662306a36Sopenharmony_ciparser = argparse.ArgumentParser(description=desc,
5762306a36Sopenharmony_ci                                 formatter_class=argparse.RawTextHelpFormatter)
5862306a36Sopenharmony_ciargs = parser.parse_args()
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cidef err(s):
6162306a36Sopenharmony_ci    print(s, file=sys.stderr, flush=True)
6262306a36Sopenharmony_ci    sys.exit(1)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cidef cpumask_str(cpumask):
6562306a36Sopenharmony_ci    output = ""
6662306a36Sopenharmony_ci    base = 0
6762306a36Sopenharmony_ci    v = 0
6862306a36Sopenharmony_ci    for cpu in for_each_cpu(cpumask[0]):
6962306a36Sopenharmony_ci        while cpu - base >= 32:
7062306a36Sopenharmony_ci            output += f'{hex(v)} '
7162306a36Sopenharmony_ci            base += 32
7262306a36Sopenharmony_ci            v = 0
7362306a36Sopenharmony_ci        v |= 1 << (cpu - base)
7462306a36Sopenharmony_ci    if v > 0:
7562306a36Sopenharmony_ci        output += f'{v:08x}'
7662306a36Sopenharmony_ci    return output.strip()
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciworker_pool_idr         = prog['worker_pool_idr']
7962306a36Sopenharmony_ciworkqueues              = prog['workqueues']
8062306a36Sopenharmony_ciwq_unbound_cpumask      = prog['wq_unbound_cpumask']
8162306a36Sopenharmony_ciwq_pod_types            = prog['wq_pod_types']
8262306a36Sopenharmony_ciwq_affn_dfl             = prog['wq_affn_dfl']
8362306a36Sopenharmony_ciwq_affn_names           = prog['wq_affn_names']
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciWQ_UNBOUND              = prog['WQ_UNBOUND']
8662306a36Sopenharmony_ciWQ_ORDERED              = prog['__WQ_ORDERED']
8762306a36Sopenharmony_ciWQ_MEM_RECLAIM          = prog['WQ_MEM_RECLAIM']
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciWQ_AFFN_CPU             = prog['WQ_AFFN_CPU']
9062306a36Sopenharmony_ciWQ_AFFN_SMT             = prog['WQ_AFFN_SMT']
9162306a36Sopenharmony_ciWQ_AFFN_CACHE           = prog['WQ_AFFN_CACHE']
9262306a36Sopenharmony_ciWQ_AFFN_NUMA            = prog['WQ_AFFN_NUMA']
9362306a36Sopenharmony_ciWQ_AFFN_SYSTEM          = prog['WQ_AFFN_SYSTEM']
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ciprint('Affinity Scopes')
9662306a36Sopenharmony_ciprint('===============')
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciprint(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}')
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cidef print_pod_type(pt):
10162306a36Sopenharmony_ci    print(f'  nr_pods  {pt.nr_pods.value_()}')
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci    print('  pod_cpus', end='')
10462306a36Sopenharmony_ci    for pod in range(pt.nr_pods):
10562306a36Sopenharmony_ci        print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='')
10662306a36Sopenharmony_ci    print('')
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci    print('  pod_node', end='')
10962306a36Sopenharmony_ci    for pod in range(pt.nr_pods):
11062306a36Sopenharmony_ci        print(f' [{pod}]={pt.pod_node[pod].value_()}', end='')
11162306a36Sopenharmony_ci    print('')
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci    print(f'  cpu_pod ', end='')
11462306a36Sopenharmony_ci    for cpu in for_each_possible_cpu(prog):
11562306a36Sopenharmony_ci        print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='')
11662306a36Sopenharmony_ci    print('')
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cifor affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]:
11962306a36Sopenharmony_ci    print('')
12062306a36Sopenharmony_ci    print(f'{wq_affn_names[affn].string_().decode().upper()}{" (default)" if affn == wq_affn_dfl else ""}')
12162306a36Sopenharmony_ci    print_pod_type(wq_pod_types[affn])
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciprint('')
12462306a36Sopenharmony_ciprint('Worker Pools')
12562306a36Sopenharmony_ciprint('============')
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cimax_pool_id_len = 0
12862306a36Sopenharmony_cimax_ref_len = 0
12962306a36Sopenharmony_cifor pi, pool in idr_for_each(worker_pool_idr):
13062306a36Sopenharmony_ci    pool = drgn.Object(prog, 'struct worker_pool', address=pool)
13162306a36Sopenharmony_ci    max_pool_id_len = max(max_pool_id_len, len(f'{pi}'))
13262306a36Sopenharmony_ci    max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}'))
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cifor pi, pool in idr_for_each(worker_pool_idr):
13562306a36Sopenharmony_ci    pool = drgn.Object(prog, 'struct worker_pool', address=pool)
13662306a36Sopenharmony_ci    print(f'pool[{pi:0{max_pool_id_len}}] ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='')
13762306a36Sopenharmony_ci    print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='')
13862306a36Sopenharmony_ci    if pool.cpu >= 0:
13962306a36Sopenharmony_ci        print(f'cpu={pool.cpu.value_():3}', end='')
14062306a36Sopenharmony_ci    else:
14162306a36Sopenharmony_ci        print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='')
14262306a36Sopenharmony_ci        print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='')
14362306a36Sopenharmony_ci        if pool.attrs.affn_strict:
14462306a36Sopenharmony_ci            print(' strict', end='')
14562306a36Sopenharmony_ci    print('')
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciprint('')
14862306a36Sopenharmony_ciprint('Workqueue CPU -> pool')
14962306a36Sopenharmony_ciprint('=====================')
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciprint('[    workqueue     \     type   CPU', end='')
15262306a36Sopenharmony_cifor cpu in for_each_possible_cpu(prog):
15362306a36Sopenharmony_ci    print(f' {cpu:{max_pool_id_len}}', end='')
15462306a36Sopenharmony_ciprint(' dfl]')
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cifor wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'):
15762306a36Sopenharmony_ci    print(f'{wq.name.string_().decode()[-24:]:24}', end='')
15862306a36Sopenharmony_ci    if wq.flags & WQ_UNBOUND:
15962306a36Sopenharmony_ci        if wq.flags & WQ_ORDERED:
16062306a36Sopenharmony_ci            print(' ordered   ', end='')
16162306a36Sopenharmony_ci        else:
16262306a36Sopenharmony_ci            print(' unbound', end='')
16362306a36Sopenharmony_ci            if wq.unbound_attrs.affn_strict:
16462306a36Sopenharmony_ci                print(',S ', end='')
16562306a36Sopenharmony_ci            else:
16662306a36Sopenharmony_ci                print('   ', end='')
16762306a36Sopenharmony_ci    else:
16862306a36Sopenharmony_ci        print(' percpu    ', end='')
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci    for cpu in for_each_possible_cpu(prog):
17162306a36Sopenharmony_ci        pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_()
17262306a36Sopenharmony_ci        field_len = max(len(str(cpu)), max_pool_id_len)
17362306a36Sopenharmony_ci        print(f' {pool_id:{field_len}}', end='')
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci    if wq.flags & WQ_UNBOUND:
17662306a36Sopenharmony_ci        print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='')
17762306a36Sopenharmony_ci    print('')
178