Files
linux/tools/testing/selftests/damon/drgn_dump_damon_status.py
SeongJae Park 53298afe45 mm/damon: rename damos->filters to damos->core_filters
DAMOS filters that are handled by the ops layer are linked to
damos->ops_filters.  Owing to the ops_ prefix on the name, it is easy to
understand it is for ops layer handled filters.  The other types of
filters, which are handled by the core layer, are linked to
damos->filters.  Because of the name, it is easy to confuse the list is
there for not only core layer handled ones but all filters.  Avoid such
confusions by renaming the field to core_filters.

Link: https://lkml.kernel.org/r/20251112154114.66053-3-sj@kernel.org
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: Brendan Higgins <brendan.higgins@linux.dev>
Cc: David Gow <davidgow@google.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-11-20 13:44:01 -08:00

224 lines
6.4 KiB
Python
Executable File

#!/usr/bin/env drgn
# SPDX-License-Identifier: GPL-2.0
'''
Read DAMON context data and dump as a json string.
'''
import drgn
from drgn import FaultError, NULL, Object, cast, container_of, execscript, offsetof, reinterpret, sizeof
from drgn.helpers.common import *
from drgn.helpers.linux import *
import json
import sys
if "prog" not in globals():
try:
prog = drgn.get_default_prog()
except drgn.NoDefaultProgramError:
prog = drgn.program_from_kernel()
drgn.set_default_prog(prog)
def to_dict(object, attr_name_converter):
d = {}
for attr_name, converter in attr_name_converter:
d[attr_name] = converter(getattr(object, attr_name))
return d
def ops_to_dict(ops):
return to_dict(ops, [
['id', int],
])
def intervals_goal_to_dict(goal):
return to_dict(goal, [
['access_bp', int],
['aggrs', int],
['min_sample_us', int],
['max_sample_us', int],
])
def attrs_to_dict(attrs):
return to_dict(attrs, [
['sample_interval', int],
['aggr_interval', int],
['ops_update_interval', int],
['intervals_goal', intervals_goal_to_dict],
['min_nr_regions', int],
['max_nr_regions', int],
])
def addr_range_to_dict(addr_range):
return to_dict(addr_range, [
['start', int],
['end', int],
])
def region_to_dict(region):
return to_dict(region, [
['ar', addr_range_to_dict],
['sampling_addr', int],
['nr_accesses', int],
['nr_accesses_bp', int],
['age', int],
])
def regions_to_list(regions):
return [region_to_dict(r)
for r in list_for_each_entry(
'struct damon_region', regions.address_of_(), 'list')]
def target_to_dict(target):
return to_dict(target, [
['pid', int],
['nr_regions', int],
['regions_list', regions_to_list],
['obsolete', bool],
])
def targets_to_list(targets):
return [target_to_dict(t)
for t in list_for_each_entry(
'struct damon_target', targets.address_of_(), 'list')]
def damos_access_pattern_to_dict(pattern):
return to_dict(pattern, [
['min_sz_region', int],
['max_sz_region', int],
['min_nr_accesses', int],
['max_nr_accesses', int],
['min_age_region', int],
['max_age_region', int],
])
def damos_quota_goal_to_dict(goal):
return to_dict(goal, [
['metric', int],
['target_value', int],
['current_value', int],
['last_psi_total', int],
['nid', int],
])
def damos_quota_goals_to_list(goals):
return [damos_quota_goal_to_dict(g)
for g in list_for_each_entry(
'struct damos_quota_goal', goals.address_of_(), 'list')]
def damos_quota_to_dict(quota):
return to_dict(quota, [
['reset_interval', int],
['ms', int], ['sz', int],
['goals', damos_quota_goals_to_list],
['esz', int],
['weight_sz', int],
['weight_nr_accesses', int],
['weight_age', int],
])
def damos_watermarks_to_dict(watermarks):
return to_dict(watermarks, [
['metric', int],
['interval', int],
['high', int], ['mid', int], ['low', int],
])
def damos_migrate_dests_to_dict(dests):
nr_dests = int(dests.nr_dests)
node_id_arr = []
weight_arr = []
for i in range(nr_dests):
node_id_arr.append(int(dests.node_id_arr[i]))
weight_arr.append(int(dests.weight_arr[i]))
return {
'node_id_arr': node_id_arr,
'weight_arr': weight_arr,
'nr_dests': nr_dests,
}
def damos_filter_to_dict(damos_filter):
filter_type_keyword = {
0: 'anon',
1: 'active',
2: 'memcg',
3: 'young',
4: 'hugepage_size',
5: 'unmapped',
6: 'addr',
7: 'target'
}
dict_ = {
'type': filter_type_keyword[int(damos_filter.type)],
'matching': bool(damos_filter.matching),
'allow': bool(damos_filter.allow),
}
type_ = dict_['type']
if type_ == 'memcg':
dict_['memcg_id'] = int(damos_filter.memcg_id)
elif type_ == 'addr':
dict_['addr_range'] = [int(damos_filter.addr_range.start),
int(damos_filter.addr_range.end)]
elif type_ == 'target':
dict_['target_idx'] = int(damos_filter.target_idx)
elif type_ == 'hugeapge_size':
dict_['sz_range'] = [int(damos_filter.sz_range.min),
int(damos_filter.sz_range.max)]
return dict_
def scheme_to_dict(scheme):
dict_ = to_dict(scheme, [
['pattern', damos_access_pattern_to_dict],
['action', int],
['apply_interval_us', int],
['quota', damos_quota_to_dict],
['wmarks', damos_watermarks_to_dict],
['target_nid', int],
['migrate_dests', damos_migrate_dests_to_dict],
])
core_filters = []
for f in list_for_each_entry(
'struct damos_filter', scheme.core_filters.address_of_(), 'list'):
core_filters.append(damos_filter_to_dict(f))
dict_['core_filters'] = core_filters
ops_filters = []
for f in list_for_each_entry(
'struct damos_filter', scheme.ops_filters.address_of_(), 'list'):
ops_filters.append(damos_filter_to_dict(f))
dict_['ops_filters'] = ops_filters
return dict_
def schemes_to_list(schemes):
return [scheme_to_dict(s)
for s in list_for_each_entry(
'struct damos', schemes.address_of_(), 'list')]
def damon_ctx_to_dict(ctx):
return to_dict(ctx, [
['ops', ops_to_dict],
['attrs', attrs_to_dict],
['adaptive_targets', targets_to_list],
['schemes', schemes_to_list],
])
def main():
if len(sys.argv) < 3:
print('Usage: %s <kdamond pid> <file>' % sys.argv[0])
exit(1)
pid = int(sys.argv[1])
file_to_store = sys.argv[2]
kthread_data = cast('struct kthread *',
find_task(prog, pid).worker_private).data
ctx = cast('struct damon_ctx *', kthread_data)
status = {'contexts': [damon_ctx_to_dict(ctx)]}
if file_to_store == 'stdout':
print(json.dumps(status, indent=4))
else:
with open(file_to_store, 'w') as f:
json.dump(status, f, indent=4)
if __name__ == '__main__':
main()