The new update_schemes_quota_goals sysfs command allows users to manually
update the current_value of quota goals.

Add a selftest for the command. The test writes a dummy value to
current_value, executes the update command, and verifies that the dummy
value is successfully overwritten by the kernel.

Assisted-by: Antigravity:Gemini-3.1-Pro
Signed-off-by: Maksym Shcherba <[email protected]>
---
 tools/testing/selftests/damon/Makefile        |  1 +
 .../damon/sysfs_update_schemes_quota_goals.py | 86 +++++++++++++++++++
 2 files changed, 87 insertions(+)
 create mode 100755 
tools/testing/selftests/damon/sysfs_update_schemes_quota_goals.py

diff --git a/tools/testing/selftests/damon/Makefile 
b/tools/testing/selftests/damon/Makefile
index 2180c328a825..a692ebaa6c8a 100644
--- a/tools/testing/selftests/damon/Makefile
+++ b/tools/testing/selftests/damon/Makefile
@@ -13,6 +13,7 @@ TEST_PROGS += sysfs.py
 TEST_PROGS += sysfs_update_schemes_tried_regions_wss_estimation.py
 TEST_PROGS += damos_quota.py damos_quota_goal.py damos_apply_interval.py
 TEST_PROGS += damos_tried_regions.py damon_nr_regions.py
+TEST_PROGS += sysfs_update_schemes_quota_goals.py
 TEST_PROGS += reclaim.sh lru_sort.sh
 
 # regression tests (reproducers of previously found bugs)
diff --git a/tools/testing/selftests/damon/sysfs_update_schemes_quota_goals.py 
b/tools/testing/selftests/damon/sysfs_update_schemes_quota_goals.py
new file mode 100755
index 000000000000..745b97f75bc2
--- /dev/null
+++ b/tools/testing/selftests/damon/sysfs_update_schemes_quota_goals.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+Test the update_schemes_quota_goals sysfs command.
+
+Start DAMON with a scheme that has a some_mem_psi_us quota goal.  Write a
+physically impossible dummy value to the goal's current_value sysfs file.
+Wait for a while, ensure the dummy value is not overwritten asynchronously,
+then write 'update_schemes_quota_goals' to the state file and verify that
+the dummy value is overwritten by the kernel.
+"""
+
+import os
+import time
+
+import _damon_sysfs
+
+
+def main():
+    goal = _damon_sysfs.DamosQuotaGoal(
+            metric=_damon_sysfs.qgoal_metric_some_mem_psi_us,
+            target_value=1000)
+    kdamonds = _damon_sysfs.Kdamonds([_damon_sysfs.Kdamond(
+            contexts=[_damon_sysfs.DamonCtx(
+                ops='paddr',
+                schemes=[_damon_sysfs.Damos(
+                    action='stat',
+                    quota=_damon_sysfs.DamosQuota(
+                        goals=[goal], reset_interval_ms=100),
+                    )]  # schemes
+                )]  # contexts
+            )])  # kdamonds
+
+    err = kdamonds.start()
+    if err is not None:
+        print('kdamond start failed: %s' % err)
+        exit(1)
+
+    # Write a dummy value to current_value to ensure the command actually
+    # overwrites it. We use 2x the quota reset interval in microseconds,
+    # which is a physically impossible value for the kernel to measure.
+    impossible_value = goal.quota.reset_interval_ms * 2000
+    err = _damon_sysfs.write_file(
+            os.path.join(goal.sysfs_dir(), 'current_value'),
+            '%d' % impossible_value)
+    if err is not None:
+        kdamonds.stop()
+        print('Writing dummy current_value failed: %s' % err)
+        exit(1)
+
+    # wait a couple of aggregation intervals so that the kernel has a chance
+    # to compute the first current_value measurement
+    time.sleep(0.5)
+
+    content, err = _damon_sysfs.read_file(
+            os.path.join(goal.sysfs_dir(), 'current_value'))
+    if err is not None:
+        kdamonds.stop()
+        print('Reading current_value before update failed: %s' % err)
+        exit(1)
+    if int(content) != impossible_value:
+        kdamonds.stop()
+        print('current_value changed before update (%s)' % content)
+        exit(1)
+
+    err = kdamonds.kdamonds[0].update_schemes_quota_goals()
+    if err is not None:
+        kdamonds.stop()
+        print('update_schemes_quota_goals failed: %s' % err)
+        exit(1)
+
+    # current_value must be updated and different from our dummy value
+    if goal.current_value is None or goal.current_value == impossible_value:
+        kdamonds.stop()
+        print('update_schemes_quota_goals failed to update current_value')
+        exit(1)
+
+    print('current_value after update_schemes_quota_goals: %d' %
+          goal.current_value)
+
+    kdamonds.stop()
+
+
+if __name__ == '__main__':
+    main()
-- 
2.43.0


Reply via email to