xref: /linux/tools/testing/selftests/damon/drgn_dump_damon_status.py (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
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