drgn_dump_damon_status.py 6.4 KB

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