1f3e8e1e5SSeongJae Park#!/usr/bin/env drgn 2f3e8e1e5SSeongJae Park# SPDX-License-Identifier: GPL-2.0 3f3e8e1e5SSeongJae Park 4f3e8e1e5SSeongJae Park''' 5f3e8e1e5SSeongJae ParkRead DAMON context data and dump as a json string. 6f3e8e1e5SSeongJae Park''' 7f3e8e1e5SSeongJae Parkimport drgn 8f3e8e1e5SSeongJae Parkfrom drgn import FaultError, NULL, Object, cast, container_of, execscript, offsetof, reinterpret, sizeof 9f3e8e1e5SSeongJae Parkfrom drgn.helpers.common import * 10f3e8e1e5SSeongJae Parkfrom drgn.helpers.linux import * 11f3e8e1e5SSeongJae Park 12f3e8e1e5SSeongJae Parkimport json 13f3e8e1e5SSeongJae Parkimport sys 14f3e8e1e5SSeongJae Park 15f3e8e1e5SSeongJae Parkif "prog" not in globals(): 16f3e8e1e5SSeongJae Park try: 17f3e8e1e5SSeongJae Park prog = drgn.get_default_prog() 18f3e8e1e5SSeongJae Park except drgn.NoDefaultProgramError: 19f3e8e1e5SSeongJae Park prog = drgn.program_from_kernel() 20f3e8e1e5SSeongJae Park drgn.set_default_prog(prog) 21f3e8e1e5SSeongJae Park 22f3e8e1e5SSeongJae Parkdef to_dict(object, attr_name_converter): 23f3e8e1e5SSeongJae Park d = {} 24f3e8e1e5SSeongJae Park for attr_name, converter in attr_name_converter: 25f3e8e1e5SSeongJae Park d[attr_name] = converter(getattr(object, attr_name)) 26f3e8e1e5SSeongJae Park return d 27f3e8e1e5SSeongJae Park 28eb413daaSSeongJae Parkdef ops_to_dict(ops): 29eb413daaSSeongJae Park return to_dict(ops, [ 30eb413daaSSeongJae Park ['id', int], 31eb413daaSSeongJae Park ]) 32eb413daaSSeongJae Park 33f3e8e1e5SSeongJae Parkdef intervals_goal_to_dict(goal): 34f3e8e1e5SSeongJae Park return to_dict(goal, [ 35f3e8e1e5SSeongJae Park ['access_bp', int], 36f3e8e1e5SSeongJae Park ['aggrs', int], 37f3e8e1e5SSeongJae Park ['min_sample_us', int], 38f3e8e1e5SSeongJae Park ['max_sample_us', int], 39f3e8e1e5SSeongJae Park ]) 40f3e8e1e5SSeongJae Park 41f3e8e1e5SSeongJae Parkdef attrs_to_dict(attrs): 42f3e8e1e5SSeongJae Park return to_dict(attrs, [ 43f3e8e1e5SSeongJae Park ['sample_interval', int], 44f3e8e1e5SSeongJae Park ['aggr_interval', int], 45f3e8e1e5SSeongJae Park ['ops_update_interval', int], 46f3e8e1e5SSeongJae Park ['intervals_goal', intervals_goal_to_dict], 47f3e8e1e5SSeongJae Park ['min_nr_regions', int], 48f3e8e1e5SSeongJae Park ['max_nr_regions', int], 49f3e8e1e5SSeongJae Park ]) 50f3e8e1e5SSeongJae Park 51f3e8e1e5SSeongJae Parkdef addr_range_to_dict(addr_range): 52f3e8e1e5SSeongJae Park return to_dict(addr_range, [ 53f3e8e1e5SSeongJae Park ['start', int], 54f3e8e1e5SSeongJae Park ['end', int], 55f3e8e1e5SSeongJae Park ]) 56f3e8e1e5SSeongJae Park 57f3e8e1e5SSeongJae Parkdef region_to_dict(region): 58f3e8e1e5SSeongJae Park return to_dict(region, [ 59f3e8e1e5SSeongJae Park ['ar', addr_range_to_dict], 60f3e8e1e5SSeongJae Park ['sampling_addr', int], 61f3e8e1e5SSeongJae Park ['nr_accesses', int], 62f3e8e1e5SSeongJae Park ['nr_accesses_bp', int], 63f3e8e1e5SSeongJae Park ['age', int], 64f3e8e1e5SSeongJae Park ]) 65f3e8e1e5SSeongJae Park 66f3e8e1e5SSeongJae Parkdef regions_to_list(regions): 67f3e8e1e5SSeongJae Park return [region_to_dict(r) 68f3e8e1e5SSeongJae Park for r in list_for_each_entry( 69f3e8e1e5SSeongJae Park 'struct damon_region', regions.address_of_(), 'list')] 70f3e8e1e5SSeongJae Park 71f3e8e1e5SSeongJae Parkdef target_to_dict(target): 72f3e8e1e5SSeongJae Park return to_dict(target, [ 73f3e8e1e5SSeongJae Park ['pid', int], 74f3e8e1e5SSeongJae Park ['nr_regions', int], 75f3e8e1e5SSeongJae Park ['regions_list', regions_to_list], 76f3e8e1e5SSeongJae Park ]) 77f3e8e1e5SSeongJae Park 78f3e8e1e5SSeongJae Parkdef targets_to_list(targets): 79f3e8e1e5SSeongJae Park return [target_to_dict(t) 80f3e8e1e5SSeongJae Park for t in list_for_each_entry( 81f3e8e1e5SSeongJae Park 'struct damon_target', targets.address_of_(), 'list')] 82f3e8e1e5SSeongJae Park 83f3e8e1e5SSeongJae Parkdef damos_access_pattern_to_dict(pattern): 84f3e8e1e5SSeongJae Park return to_dict(pattern, [ 85f3e8e1e5SSeongJae Park ['min_sz_region', int], 86f3e8e1e5SSeongJae Park ['max_sz_region', int], 87f3e8e1e5SSeongJae Park ['min_nr_accesses', int], 88f3e8e1e5SSeongJae Park ['max_nr_accesses', int], 89f3e8e1e5SSeongJae Park ['min_age_region', int], 90f3e8e1e5SSeongJae Park ['max_age_region', int], 91f3e8e1e5SSeongJae Park ]) 92f3e8e1e5SSeongJae Park 93f3e8e1e5SSeongJae Parkdef damos_quota_goal_to_dict(goal): 94f3e8e1e5SSeongJae Park return to_dict(goal, [ 95f3e8e1e5SSeongJae Park ['metric', int], 96f3e8e1e5SSeongJae Park ['target_value', int], 97f3e8e1e5SSeongJae Park ['current_value', int], 98f3e8e1e5SSeongJae Park ['last_psi_total', int], 99f3e8e1e5SSeongJae Park ['nid', int], 100f3e8e1e5SSeongJae Park ]) 101f3e8e1e5SSeongJae Park 102f3e8e1e5SSeongJae Parkdef damos_quota_goals_to_list(goals): 103f3e8e1e5SSeongJae Park return [damos_quota_goal_to_dict(g) 104f3e8e1e5SSeongJae Park for g in list_for_each_entry( 105f3e8e1e5SSeongJae Park 'struct damos_quota_goal', goals.address_of_(), 'list')] 106f3e8e1e5SSeongJae Park 107f3e8e1e5SSeongJae Parkdef damos_quota_to_dict(quota): 108f3e8e1e5SSeongJae Park return to_dict(quota, [ 109f3e8e1e5SSeongJae Park ['reset_interval', int], 110f3e8e1e5SSeongJae Park ['ms', int], ['sz', int], 111f3e8e1e5SSeongJae Park ['goals', damos_quota_goals_to_list], 112f3e8e1e5SSeongJae Park ['esz', int], 113f3e8e1e5SSeongJae Park ['weight_sz', int], 114f3e8e1e5SSeongJae Park ['weight_nr_accesses', int], 115f3e8e1e5SSeongJae Park ['weight_age', int], 116f3e8e1e5SSeongJae Park ]) 117f3e8e1e5SSeongJae Park 118f3e8e1e5SSeongJae Parkdef damos_watermarks_to_dict(watermarks): 119f3e8e1e5SSeongJae Park return to_dict(watermarks, [ 120f3e8e1e5SSeongJae Park ['metric', int], 121f3e8e1e5SSeongJae Park ['interval', int], 122f3e8e1e5SSeongJae Park ['high', int], ['mid', int], ['low', int], 123f3e8e1e5SSeongJae Park ]) 124f3e8e1e5SSeongJae Park 125c1a69589SSeongJae Parkdef damos_migrate_dests_to_dict(dests): 126c1a69589SSeongJae Park nr_dests = int(dests.nr_dests) 127c1a69589SSeongJae Park node_id_arr = [] 128c1a69589SSeongJae Park weight_arr = [] 129c1a69589SSeongJae Park for i in range(nr_dests): 130c1a69589SSeongJae Park node_id_arr.append(int(dests.node_id_arr[i])) 131c1a69589SSeongJae Park weight_arr.append(int(dests.weight_arr[i])) 132c1a69589SSeongJae Park return { 133c1a69589SSeongJae Park 'node_id_arr': node_id_arr, 134c1a69589SSeongJae Park 'weight_arr': weight_arr, 135c1a69589SSeongJae Park 'nr_dests': nr_dests, 136c1a69589SSeongJae Park } 137c1a69589SSeongJae Park 138*a1d52cd0SSeongJae Parkdef damos_filter_to_dict(damos_filter): 139*a1d52cd0SSeongJae Park filter_type_keyword = { 140*a1d52cd0SSeongJae Park 0: 'anon', 141*a1d52cd0SSeongJae Park 1: 'active', 142*a1d52cd0SSeongJae Park 2: 'memcg', 143*a1d52cd0SSeongJae Park 3: 'young', 144*a1d52cd0SSeongJae Park 4: 'hugepage_size', 145*a1d52cd0SSeongJae Park 5: 'unmapped', 146*a1d52cd0SSeongJae Park 6: 'addr', 147*a1d52cd0SSeongJae Park 7: 'target' 148*a1d52cd0SSeongJae Park } 149*a1d52cd0SSeongJae Park dict_ = { 150*a1d52cd0SSeongJae Park 'type': filter_type_keyword[int(damos_filter.type)], 151*a1d52cd0SSeongJae Park 'matching': bool(damos_filter.matching), 152*a1d52cd0SSeongJae Park 'allow': bool(damos_filter.allow), 153*a1d52cd0SSeongJae Park } 154*a1d52cd0SSeongJae Park type_ = dict_['type'] 155*a1d52cd0SSeongJae Park if type_ == 'memcg': 156*a1d52cd0SSeongJae Park dict_['memcg_id'] = int(damos_filter.memcg_id) 157*a1d52cd0SSeongJae Park elif type_ == 'addr': 158*a1d52cd0SSeongJae Park dict_['addr_range'] = [int(damos_filter.addr_range.start), 159*a1d52cd0SSeongJae Park int(damos_filter.addr_range.end)] 160*a1d52cd0SSeongJae Park elif type_ == 'target': 161*a1d52cd0SSeongJae Park dict_['target_idx'] = int(damos_filter.target_idx) 162*a1d52cd0SSeongJae Park elif type_ == 'hugeapge_size': 163*a1d52cd0SSeongJae Park dict_['sz_range'] = [int(damos_filter.sz_range.min), 164*a1d52cd0SSeongJae Park int(damos_filter.sz_range.max)] 165*a1d52cd0SSeongJae Park return dict_ 166*a1d52cd0SSeongJae Park 167f3e8e1e5SSeongJae Parkdef scheme_to_dict(scheme): 168*a1d52cd0SSeongJae Park dict_ = to_dict(scheme, [ 169f3e8e1e5SSeongJae Park ['pattern', damos_access_pattern_to_dict], 170f3e8e1e5SSeongJae Park ['action', int], 171f3e8e1e5SSeongJae Park ['apply_interval_us', int], 172f3e8e1e5SSeongJae Park ['quota', damos_quota_to_dict], 173f3e8e1e5SSeongJae Park ['wmarks', damos_watermarks_to_dict], 174f3e8e1e5SSeongJae Park ['target_nid', int], 175c1a69589SSeongJae Park ['migrate_dests', damos_migrate_dests_to_dict], 176f3e8e1e5SSeongJae Park ]) 177*a1d52cd0SSeongJae Park filters = [] 178*a1d52cd0SSeongJae Park for f in list_for_each_entry( 179*a1d52cd0SSeongJae Park 'struct damos_filter', scheme.filters.address_of_(), 'list'): 180*a1d52cd0SSeongJae Park filters.append(damos_filter_to_dict(f)) 181*a1d52cd0SSeongJae Park dict_['filters'] = filters 182*a1d52cd0SSeongJae Park ops_filters = [] 183*a1d52cd0SSeongJae Park for f in list_for_each_entry( 184*a1d52cd0SSeongJae Park 'struct damos_filter', scheme.ops_filters.address_of_(), 'list'): 185*a1d52cd0SSeongJae Park ops_filters.append(damos_filter_to_dict(f)) 186*a1d52cd0SSeongJae Park dict_['ops_filters'] = ops_filters 187*a1d52cd0SSeongJae Park 188*a1d52cd0SSeongJae Park return dict_ 189f3e8e1e5SSeongJae Park 190f3e8e1e5SSeongJae Parkdef schemes_to_list(schemes): 191f3e8e1e5SSeongJae Park return [scheme_to_dict(s) 192f3e8e1e5SSeongJae Park for s in list_for_each_entry( 193f3e8e1e5SSeongJae Park 'struct damos', schemes.address_of_(), 'list')] 194f3e8e1e5SSeongJae Park 195f3e8e1e5SSeongJae Parkdef damon_ctx_to_dict(ctx): 196f3e8e1e5SSeongJae Park return to_dict(ctx, [ 197eb413daaSSeongJae Park ['ops', ops_to_dict], 198f3e8e1e5SSeongJae Park ['attrs', attrs_to_dict], 199f3e8e1e5SSeongJae Park ['adaptive_targets', targets_to_list], 200f3e8e1e5SSeongJae Park ['schemes', schemes_to_list], 201f3e8e1e5SSeongJae Park ]) 202f3e8e1e5SSeongJae Park 203f3e8e1e5SSeongJae Parkdef main(): 204f3e8e1e5SSeongJae Park if len(sys.argv) < 3: 205f3e8e1e5SSeongJae Park print('Usage: %s <kdamond pid> <file>' % sys.argv[0]) 206f3e8e1e5SSeongJae Park exit(1) 207f3e8e1e5SSeongJae Park 208f3e8e1e5SSeongJae Park pid = int(sys.argv[1]) 209f3e8e1e5SSeongJae Park file_to_store = sys.argv[2] 210f3e8e1e5SSeongJae Park 211f3e8e1e5SSeongJae Park kthread_data = cast('struct kthread *', 212f3e8e1e5SSeongJae Park find_task(prog, pid).worker_private).data 213f3e8e1e5SSeongJae Park ctx = cast('struct damon_ctx *', kthread_data) 214f3e8e1e5SSeongJae Park status = {'contexts': [damon_ctx_to_dict(ctx)]} 215f3e8e1e5SSeongJae Park if file_to_store == 'stdout': 216f3e8e1e5SSeongJae Park print(json.dumps(status, indent=4)) 217f3e8e1e5SSeongJae Park else: 218f3e8e1e5SSeongJae Park with open(file_to_store, 'w') as f: 219f3e8e1e5SSeongJae Park json.dump(status, f, indent=4) 220f3e8e1e5SSeongJae Park 221f3e8e1e5SSeongJae Parkif __name__ == '__main__': 222f3e8e1e5SSeongJae Park main() 223