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