1 # SPDX-License-Identifier: GPL-2.0
8 with
open('/proc/mounts', 'r') as f
:
10 dev_name
, mount_point
, dev_fs
= line
.split()[:3]
12 sysfs_root
= '%s/kernel/mm/damon/admin' % mount_point
14 if sysfs_root
is None:
15 print('Seems sysfs not mounted?')
18 def write_file(path
, string
):
19 "Returns error string if failed, or None otherwise"
20 string
= '%s' % string
22 with
open(path
, 'w') as f
:
24 except Exception as e
:
29 '''Returns the read content and error string. The read content is None if
32 with
open(path
, 'r') as f
:
34 except Exception as e
:
37 class DamosAccessPattern
:
43 def __init__(self
, size
=None, nr_accesses
=None, age
=None):
45 self
.nr_accesses
= nr_accesses
49 self
.size
= [0, 2**64 - 1]
50 if self
.nr_accesses
is None:
51 self
.nr_accesses
= [0, 2**64 - 1]
53 self
.age
= [0, 2**64 - 1]
56 return os
.path
.join(self
.scheme
.sysfs_dir(), 'access_pattern')
60 os
.path
.join(self
.sysfs_dir(), 'sz', 'min'), self
.size
[0])
64 os
.path
.join(self
.sysfs_dir(), 'sz', 'max'), self
.size
[1])
67 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'nr_accesses', 'min'),
71 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'nr_accesses', 'max'),
76 os
.path
.join(self
.sysfs_dir(), 'age', 'min'), self
.age
[0])
80 os
.path
.join(self
.sysfs_dir(), 'age', 'max'), self
.age
[1])
84 qgoal_metric_user_input
= 'user_input'
85 qgoal_metric_some_mem_psi_us
= 'some_mem_psi_us'
86 qgoal_metrics
= [qgoal_metric_user_input
, qgoal_metric_some_mem_psi_us
]
92 effective_bytes
= None
93 quota
= None # owner quota
96 def __init__(self
, metric
, target_value
=10000, current_value
=0):
98 self
.target_value
= target_value
99 self
.current_value
= current_value
102 return os
.path
.join(self
.quota
.sysfs_dir(), 'goals', '%d' % self
.idx
)
105 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'target_metric'),
109 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'target_value'),
113 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'current_value'),
120 sz
= None # size quota, in bytes
121 ms
= None # time quota
122 goals
= None # quota goals
123 reset_interval_ms
= None # quota reset interval
124 scheme
= None # owner scheme
126 def __init__(self
, sz
=0, ms
=0, goals
=None, reset_interval_ms
=0):
129 self
.reset_interval_ms
= reset_interval_ms
130 self
.goals
= goals
if goals
is not None else []
131 for idx
, goal
in enumerate(self
.goals
):
136 return os
.path
.join(self
.scheme
.sysfs_dir(), 'quotas')
139 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'bytes'), self
.sz
)
142 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'ms'), self
.ms
)
145 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'reset_interval_ms'),
146 self
.reset_interval_ms
)
150 nr_goals_file
= os
.path
.join(self
.sysfs_dir(), 'goals', 'nr_goals')
151 content
, err
= read_file(nr_goals_file
)
154 if int(content
) != len(self
.goals
):
155 err
= write_file(nr_goals_file
, len(self
.goals
))
158 for goal
in self
.goals
:
171 def __init__(self
, nr_tried
, sz_tried
, nr_applied
, sz_applied
, qt_exceeds
):
172 self
.nr_tried
= nr_tried
173 self
.sz_tried
= sz_tried
174 self
.nr_applied
= nr_applied
175 self
.sz_applied
= sz_applied
176 self
.qt_exceeds
= qt_exceeds
178 class DamosTriedRegion
:
179 def __init__(self
, start
, end
, nr_accesses
, age
):
182 self
.nr_accesses
= nr_accesses
187 access_pattern
= None
189 apply_interval_us
= None
190 # todo: Support watermarks, stats
197 def __init__(self
, action
='stat', access_pattern
=DamosAccessPattern(),
198 quota
=DamosQuota(), apply_interval_us
=0):
200 self
.access_pattern
= access_pattern
201 self
.access_pattern
.scheme
= self
203 self
.quota
.scheme
= self
204 self
.apply_interval_us
= apply_interval_us
208 self
.context
.sysfs_dir(), 'schemes', '%d' % self
.idx
)
211 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'action'), self
.action
)
214 err
= self
.access_pattern
.stage()
217 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'apply_interval_us'),
218 '%d' % self
.apply_interval_us
)
222 err
= self
.quota
.stage()
228 os
.path
.join(self
.sysfs_dir(), 'watermarks', 'metric'), 'none')
234 os
.path
.join(self
.sysfs_dir(), 'filters', 'nr_filters'), '0')
240 # todo: Support target regions if test is made
244 def __init__(self
, pid
):
249 self
.context
.sysfs_dir(), 'targets', '%d' % self
.idx
)
253 os
.path
.join(self
.sysfs_dir(), 'regions', 'nr_regions'), '0')
257 os
.path
.join(self
.sysfs_dir(), 'pid_target'), self
.pid
)
263 min_nr_regions
= None
264 max_nr_regions
= None
267 def __init__(self
, sample_us
=5000, aggr_us
=100000, update_us
=1000000,
268 min_nr_regions
=10, max_nr_regions
=1000):
269 self
.sample_us
= sample_us
270 self
.aggr_us
= aggr_us
271 self
.update_us
= update_us
272 self
.min_nr_regions
= min_nr_regions
273 self
.max_nr_regions
= max_nr_regions
275 def interval_sysfs_dir(self
):
276 return os
.path
.join(self
.context
.sysfs_dir(), 'monitoring_attrs',
279 def nr_regions_range_sysfs_dir(self
):
280 return os
.path
.join(self
.context
.sysfs_dir(), 'monitoring_attrs',
284 err
= write_file(os
.path
.join(self
.interval_sysfs_dir(), 'sample_us'),
288 err
= write_file(os
.path
.join(self
.interval_sysfs_dir(), 'aggr_us'),
292 err
= write_file(os
.path
.join(self
.interval_sysfs_dir(), 'update_us'),
298 os
.path
.join(self
.nr_regions_range_sysfs_dir(), 'min'),
304 os
.path
.join(self
.nr_regions_range_sysfs_dir(), 'max'),
311 monitoring_attrs
= None
317 def __init__(self
, ops
='paddr', monitoring_attrs
=DamonAttrs(), targets
=[],
320 self
.monitoring_attrs
= monitoring_attrs
321 self
.monitoring_attrs
.context
= self
323 self
.targets
= targets
324 for idx
, target
in enumerate(self
.targets
):
326 target
.context
= self
328 self
.schemes
= schemes
329 for idx
, scheme
in enumerate(self
.schemes
):
331 scheme
.context
= self
334 return os
.path
.join(self
.kdamond
.sysfs_dir(), 'contexts',
339 os
.path
.join(self
.sysfs_dir(), 'operations'), self
.ops
)
342 err
= self
.monitoring_attrs
.stage()
346 nr_targets_file
= os
.path
.join(
347 self
.sysfs_dir(), 'targets', 'nr_targets')
348 content
, err
= read_file(nr_targets_file
)
351 if int(content
) != len(self
.targets
):
352 err
= write_file(nr_targets_file
, '%d' % len(self
.targets
))
355 for target
in self
.targets
:
360 nr_schemes_file
= os
.path
.join(
361 self
.sysfs_dir(), 'schemes', 'nr_schemes')
362 content
, err
= read_file(nr_schemes_file
)
365 if int(content
) != len(self
.schemes
):
366 err
= write_file(nr_schemes_file
, '%d' % len(self
.schemes
))
369 for scheme
in self
.schemes
:
379 idx
= None # index of this kdamond between siblings
380 kdamonds
= None # parent
382 def __init__(self
, contexts
=[]):
383 self
.contexts
= contexts
384 for idx
, context
in enumerate(self
.contexts
):
386 context
.kdamond
= self
389 return os
.path
.join(self
.kdamonds
.sysfs_dir(), '%d' % self
.idx
)
392 nr_contexts_file
= os
.path
.join(self
.sysfs_dir(),
393 'contexts', 'nr_contexts')
394 content
, err
= read_file(nr_contexts_file
)
397 if int(content
) != len(self
.contexts
):
398 err
= write_file(nr_contexts_file
, '%d' % len(self
.contexts
))
402 for context
in self
.contexts
:
403 err
= context
.stage()
406 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'), 'on')
410 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'), 'off')
413 def update_schemes_tried_regions(self
):
414 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'),
415 'update_schemes_tried_regions')
418 for context
in self
.contexts
:
419 for scheme
in context
.schemes
:
421 tried_regions_dir
= os
.path
.join(
422 scheme
.sysfs_dir(), 'tried_regions')
423 for filename
in os
.listdir(
424 os
.path
.join(scheme
.sysfs_dir(), 'tried_regions')):
425 tried_region_dir
= os
.path
.join(tried_regions_dir
, filename
)
426 if not os
.path
.isdir(tried_region_dir
):
429 for f
in ['start', 'end', 'nr_accesses', 'age']:
430 content
, err
= read_file(
431 os
.path
.join(tried_region_dir
, f
))
434 region_values
.append(int(content
))
435 tried_regions
.append(DamosTriedRegion(*region_values
))
436 scheme
.tried_regions
= tried_regions
438 def update_schemes_tried_bytes(self
):
439 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'),
440 'update_schemes_tried_bytes')
443 for context
in self
.contexts
:
444 for scheme
in context
.schemes
:
445 content
, err
= read_file(os
.path
.join(scheme
.sysfs_dir(),
446 'tried_regions', 'total_bytes'))
449 scheme
.tried_bytes
= int(content
)
451 def update_schemes_stats(self
):
452 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'),
453 'update_schemes_stats')
456 for context
in self
.contexts
:
457 for scheme
in context
.schemes
:
459 for stat
in ['nr_tried', 'sz_tried', 'nr_applied',
460 'sz_applied', 'qt_exceeds']:
461 content
, err
= read_file(
462 os
.path
.join(scheme
.sysfs_dir(), 'stats', stat
))
465 stat_values
.append(int(content
))
466 scheme
.stats
= DamosStats(*stat_values
)
468 def update_schemes_effective_quotas(self
):
469 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'),
470 'update_schemes_effective_quotas')
473 for context
in self
.contexts
:
474 for scheme
in context
.schemes
:
475 for goal
in scheme
.quota
.goals
:
476 content
, err
= read_file(
477 os
.path
.join(scheme
.quota
.sysfs_dir(),
481 goal
.effective_bytes
= int(content
)
485 nr_contexts_file
= os
.path
.join(self
.sysfs_dir(),
486 'contexts', 'nr_contexts')
487 content
, err
= read_file(nr_contexts_file
)
490 if int(content
) != len(self
.contexts
):
491 err
= write_file(nr_contexts_file
, '%d' % len(self
.contexts
))
495 for context
in self
.contexts
:
496 err
= context
.stage()
499 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'state'), 'commit')
503 def commit_schemes_quota_goals(self
):
504 for context
in self
.contexts
:
505 for scheme
in context
.schemes
:
506 for goal
in scheme
.quota
.goals
:
509 print('commit_schemes_quota_goals failed stagign: %s'%
512 return write_file(os
.path
.join(self
.sysfs_dir(), 'state'),
513 'commit_schemes_quota_goals')
518 def __init__(self
, kdamonds
=[]):
519 self
.kdamonds
= kdamonds
520 for idx
, kdamond
in enumerate(self
.kdamonds
):
522 kdamond
.kdamonds
= self
525 return os
.path
.join(sysfs_root
, 'kdamonds')
528 err
= write_file(os
.path
.join(self
.sysfs_dir(), 'nr_kdamonds'),
529 '%s' % len(self
.kdamonds
))
532 for kdamond
in self
.kdamonds
:
533 err
= kdamond
.start()
539 for kdamond
in self
.kdamonds
: