1 #!/usr/bin/env drgn 2 # 3 # Copyright (C) 2020 Roman Gushchin <guro@fb.co 4 # Copyright (C) 2020 Facebook 5 6 from os import stat 7 import argparse 8 import sys 9 10 from drgn.helpers.linux import list_for_each_e 11 from drgn.helpers.linux import for_each_page 12 from drgn.helpers.linux.cpumask import for_eac 13 from drgn.helpers.linux.percpu import per_cpu_ 14 from drgn import container_of, FaultError, Obj 15 16 17 DESC = """ 18 This is a drgn script to provide slab statisti 19 It supports cgroup v2 and v1 and can emulate m 20 interface of cgroup v1. 21 For drgn, visit https://github.com/osandov/drg 22 """ 23 24 25 MEMCGS = {} 26 27 OO_SHIFT = 16 28 OO_MASK = ((1 << OO_SHIFT) - 1) 29 30 31 def err(s): 32 print('slabinfo.py: error: %s' % s, file=s 33 sys.exit(1) 34 35 36 def find_memcg_ids(css=prog['root_mem_cgroup'] 37 if not list_empty(css.children.address_of_ 38 for css in list_for_each_entry('struct 39 css.chi 40 'siblin 41 name = prefix + '/' + css.cgroup.k 42 memcg = container_of(css, 'struct 43 MEMCGS[css.cgroup.kn.id.value_()] 44 find_memcg_ids(css, name) 45 46 47 def is_root_cache(s): 48 try: 49 return False if s.memcg_params.root_ca 50 except AttributeError: 51 return True 52 53 54 def cache_name(s): 55 if is_root_cache(s): 56 return s.name.string_().decode('utf-8' 57 else: 58 return s.memcg_params.root_cache.name. 59 60 61 # SLUB 62 63 def oo_order(s): 64 return s.oo.x >> OO_SHIFT 65 66 67 def oo_objects(s): 68 return s.oo.x & OO_MASK 69 70 71 def count_partial(n, fn): 72 nr_objs = 0 73 for slab in list_for_each_entry('struct sl 74 'slab_list 75 nr_objs += fn(slab) 76 return nr_objs 77 78 79 def count_free(slab): 80 return slab.objects - slab.inuse 81 82 83 def slub_get_slabinfo(s, cfg): 84 nr_slabs = 0 85 nr_objs = 0 86 nr_free = 0 87 88 for node in range(cfg['nr_nodes']): 89 n = s.node[node] 90 nr_slabs += n.nr_slabs.counter.value_( 91 nr_objs += n.total_objects.counter.val 92 nr_free += count_partial(n, count_free 93 94 return {'active_objs': nr_objs - nr_free, 95 'num_objs': nr_objs, 96 'active_slabs': nr_slabs, 97 'num_slabs': nr_slabs, 98 'objects_per_slab': oo_objects(s), 99 'cache_order': oo_order(s), 100 'limit': 0, 101 'batchcount': 0, 102 'shared': 0, 103 'shared_avail': 0} 104 105 106 def cache_show(s, cfg, objs): 107 if cfg['allocator'] == 'SLUB': 108 sinfo = slub_get_slabinfo(s, cfg) 109 else: 110 err('SLAB isn\'t supported yet') 111 112 if cfg['shared_slab_pages']: 113 sinfo['active_objs'] = objs 114 sinfo['num_objs'] = objs 115 116 print('%-17s %6lu %6lu %6u %4u %4d' 117 ' : tunables %4u %4u %4u' 118 ' : slabdata %6lu %6lu %6lu' % ( 119 cache_name(s), sinfo['active_obj 120 s.size, sinfo['objects_per_slab' 121 sinfo['limit'], sinfo['batchcoun 122 sinfo['active_slabs'], sinfo['nu 123 sinfo['shared_avail'])) 124 125 126 def detect_kernel_config(): 127 cfg = {} 128 129 cfg['nr_nodes'] = prog['nr_online_nodes']. 130 131 if prog.type('struct kmem_cache').members[ 132 cfg['allocator'] = 'SLUB' 133 elif prog.type('struct kmem_cache').member 134 cfg['allocator'] = 'SLAB' 135 else: 136 err('Can\'t determine the slab allocat 137 138 cfg['shared_slab_pages'] = False 139 try: 140 if prog.type('struct obj_cgroup'): 141 cfg['shared_slab_pages'] = True 142 except: 143 pass 144 145 return cfg 146 147 148 def for_each_slab(prog): 149 PGSlab = ~prog.constant('PG_slab') 150 151 for page in for_each_page(prog): 152 try: 153 if page.page_type.value_() == PGSl 154 yield cast('struct slab *', pa 155 except FaultError: 156 pass 157 158 159 def main(): 160 parser = argparse.ArgumentParser(descripti 161 formatter 162 argparse. 163 parser.add_argument('cgroup', metavar='CGR 164 help='Target memory cg 165 args = parser.parse_args() 166 167 try: 168 cgroup_id = stat(args.cgroup).st_ino 169 find_memcg_ids() 170 memcg = MEMCGS[cgroup_id] 171 except KeyError: 172 err('Can\'t find the memory cgroup') 173 174 cfg = detect_kernel_config() 175 176 print('# name <active_objs> <nu 177 ' : tunables <limit> <batchcount> <s 178 ' : slabdata <active_slabs> <num_sla 179 180 if cfg['shared_slab_pages']: 181 obj_cgroups = set() 182 stats = {} 183 caches = {} 184 185 # find memcg pointers belonging to the 186 obj_cgroups.add(memcg.objcg.value_()) 187 for ptr in list_for_each_entry('struct 188 memcg.o 189 'list') 190 obj_cgroups.add(ptr.value_()) 191 192 # look over all slab folios and look f 193 # to the given memory cgroup 194 for slab in for_each_slab(prog): 195 objcg_vec_raw = slab.memcg_data.va 196 if objcg_vec_raw == 0: 197 continue 198 cache = slab.slab_cache 199 if not cache: 200 continue 201 addr = cache.value_() 202 caches[addr] = cache 203 # clear the lowest bit to get the 204 objcg_vec = Object(prog, 'struct o 205 value=objcg_vec 206 207 if addr not in stats: 208 stats[addr] = 0 209 210 for i in range(oo_objects(cache)): 211 if objcg_vec[i].value_() in ob 212 stats[addr] += 1 213 214 for addr in caches: 215 if stats[addr] > 0: 216 cache_show(caches[addr], cfg, 217 218 else: 219 for s in list_for_each_entry('struct k 220 memcg.kme 221 'memcg_pa 222 cache_show(s, cfg, None) 223 224 225 main()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.