mm/damon: add kunit and selftests for probes and probe weights
Subsystems (3)
SJ Park
maintainercover mm/damon: add kunit and selftests for probes and probe weights
DAMON recently introduced probes and probe weights. Add kunit and selftests for ensuring the parameters for features can be set using the core API and the sysfs ABI, respectively.
SJ Park (6):
mm/damon/tests/core-kunit: test damon_commit_filter() mm/damon/tests/core-kunit: add damon_commit_probes() test selftests/damon/_damon_sysfs: implement DamonProbes selftests/damon/drgn_dump_damon_status: dump probes selftests/damon/sysfs.py: extend commit assertion function for probes selftests/damon/sysfs.py: test damon probes
mm/damon/tests/core-kunit.h | 121 +++++++++++++++++ tools/testing/selftests/damon/_damon_sysfs.py | 123 +++++++++++++++++- .../selftests/damon/drgn_dump_damon_status.py | 32 +++++ tools/testing/selftests/damon/sysfs.py | 35 ++++- 4 files changed, 309 insertions(+), 2 deletions(-)
base-commit: 2f558ff382eed84b9ffde4dbd630a1fc4c57fab4
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 1/6 mm/damon/tests/core-kunit: test damon_commit_filter()
Add kunit test to ensure damon_commit_filter() updates destination filter as expected for valid inputs.
--- mm/damon/tests/core-kunit.h | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
mm/damon/tests/core-kunit.h +40 -0
@@ -1354,6 +1354,45 @@ static void damon_test_commit_target_regions(struct kunit *test) (unsigned long[][2]) {{3, 8}, {8, 10}}, 2); } +static void damon_test_commit_filter_for (struct kunit *test, +struct damon_filter *dst,struct damon_filter *src) +{ +damon_commit_filter (dst, src); +KUNIT_EXPECT_EQ (test, dst->type, src->type); +KUNIT_EXPECT_EQ (test, dst->matching, src->matching); +KUNIT_EXPECT_EQ (test, dst->allow, src->allow); +switch (src->type) { +case DAMOS_FILTER_TYPE_MEMCG : +KUNIT_EXPECT_EQ (test, dst->memcg_id, src->memcg_id); +break ; +default : +break ; + } +} + +static void damon_test_commit_filter (struct kunit *test) +{ +struct damon_filter dst = { + .type =DAMON_FILTER_TYPE_ANON , + .matching = false, + .allow = false, + }; + +damon_test_commit_filter_for (test, &dst, + &(struct damon_filter ){ + .type =DAMON_FILTER_TYPE_ANON , + .matching = true, + .allow = true, + }); +damon_test_commit_filter_for (test, &dst, + &(struct damon_filter ){ + .type =DAMON_FILTER_TYPE_MEMCG , + .matching = false, + .allow = false, + .memcg_id =123 , + }); +} +static void damon_test_commit_ctx (struct kunit *test) {struct damon_ctx *src, *dst;
@@ -1705,6 +1744,7 @@ static struct kunit_case damon_test_cases[] = {KUNIT_CASE (damos_test_commit_pageout),KUNIT_CASE (damos_test_commit_migrate_hot),KUNIT_CASE (damon_test_commit_target_regions), +KUNIT_CASE (damon_test_commit_filter),KUNIT_CASE (damon_test_commit_ctx),KUNIT_CASE (damos_test_filter_out), KUNIT_CASE(damon_test_feed_loop_next_input),
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter()
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The kunit test uses the wrong enum type `DAMOS_FILTER_TYPE_MEMCG` instead of…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The kunit test uses the wrong enum type DAMOS_FILTER_TYPE_MEMCG instead of DAMON_FILTER_TYPE_MEMCG when checking src->type, causing the memcg_id assertion to be silently skipped. --
--- Patch [1]: [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() --- commit e16ea26a19f85858bdb608d81842e976d30c3270
Author: SJ Park <[email protected]>
mm/damon/tests/core-kunit: test damon_commit_filter()
Add kunit test to ensure damon_commit_filter() updates destination filter as expected for valid inputs.
Quoted 5 lines
mm/damon/tests/core-kunit.h +0
-0@@ -1306,6 +1306,45 @@ static void damon_test_commit_target_regions(struct kunit *test)
[ ... ]
mm/damon/tests/core-kunit.h static void damon_test_commit_target_regions(struct kunit *test) · line 1367
Quoted 11 lines
mm/damon/tests/core-kunit.h +11
-0+static void damon_test_commit_filter_for (struct kunit *test, +struct damon_filter *dst,struct damon_filter *src) +{ +damon_commit_filter (dst, src); +KUNIT_EXPECT_EQ (test, dst->type, src->type); +KUNIT_EXPECT_EQ (test, dst->matching, src->matching); +KUNIT_EXPECT_EQ (test, dst->allow, src->allow); +switch (src->type) { +case DAMOS_FILTER_TYPE_MEMCG : +KUNIT_EXPECT_EQ (test, dst->memcg_id, src->memcg_id); +break ;
[Severity: Medium]
Will this case label ever be matched?
This code checks against DAMOS_FILTER_TYPE_MEMCG, but damon_test_commit_filter() below initializes the source filter with type DAMON_FILTER_TYPE_MEMCG.
Because of this mismatch, the switch statement falls through to the default case, and the test silently skips the assertion for memcg_id.
Quoted 7 lines
mm/damon/tests/core-kunit.h +7
-0+default : +break ; + } +} + +static void damon_test_commit_filter (struct kunit *test) +{
[ ... ]
Quoted 8 lines
mm/damon/tests/core-kunit.h +8
-0+damon_test_commit_filter_for (test, &dst, + &(struct damon_filter ){ + .type =DAMON_FILTER_TYPE_MEMCG , + .matching = false, + .allow = false, + .memcg_id =123 , + }); +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
SJ Park
maintainerRe: [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter()
Quoted 36 lines · On Wed, 29 Jul 2026 14:52:57 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The kunit test uses the wrong enum typeDAMOS_FILTER_TYPE_MEMCGinstead ofDAMON_FILTER_TYPE_MEMCGwhen checkingsrc->type, causing thememcg_idassertion to be silently skipped. ----- Patch [1]: [RFC PATCH 1/6]
mm/damon/tests/core-kunit: testdamon_commit_filter()--- commite16ea26a19f85858bdb608d81842e976d30c3270
Author: SJ Park <[email protected]>
mm/damon/tests/core-kunit: testdamon_commit_filter()Add kunit test to ensure
damon_commit_filter()updates destination filter as expected for valid inputs.Quoted 5 lines
mm/damon/tests/core-kunit.h +0
-0@@ -1306,6 +1306,45 @@ static void damon_test_commit_target_regions(struct kunit *test)[ ... ]
mm/damon/tests/core-kunit.h static void damon_test_commit_target_regions(struct kunit *test) · line 1367
Quoted 11 lines
mm/damon/tests/core-kunit.h +11
-0+static void damon_test_commit_filter_for (struct kunit *test, +struct damon_filter *dst,struct damon_filter *src) +{ +damon_commit_filter (dst, src); +KUNIT_EXPECT_EQ (test, dst->type, src->type); +KUNIT_EXPECT_EQ (test, dst->matching, src->matching); +KUNIT_EXPECT_EQ (test, dst->allow, src->allow); +switch (src->type) { +case DAMOS_FILTER_TYPE_MEMCG : +KUNIT_EXPECT_EQ (test, dst->memcg_id, src->memcg_id); +break ;[Severity: Medium]
Will this case label ever be matched?
Quoted 5 lines
This code checks against
DAMOS_FILTER_TYPE_MEMCG, butdamon_test_commit_filter()below initializes the source filter with typeDAMON_FILTER_TYPE_MEMCG.Because of this mismatch, the switch statement falls through to the default case, and the test silently skips the assertion for
memcg_id.
Good catch, I will fix.
Quoted 11 lines
Quoted 8 lines
mm/damon/tests/core-kunit.h +7
-0+default : +break ; + } +} + +static void damon_test_commit_filter (struct kunit *test) +{[ ... ]
Quoted 12 lines
Quoted 8 lines
mm/damon/tests/core-kunit.h +8
-0+damon_test_commit_filter_for (test, &dst, + &(struct damon_filter ){ + .type =DAMON_FILTER_TYPE_MEMCG , + .matching = false, + .allow = false, + .memcg_id =123 , + }); +}Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Thanks,
SJ
SJ Park
maintainerRFC PATCH 2/6 mm/damon/tests/core-kunit: add damon_commit_probes() test
In reply to SJ ParkAdd kunit test to ensure damon_commit_probes() updates destination DAMON context with source probes as expected.
--- mm/damon/tests/core-kunit.h | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
mm/damon/tests/core-kunit.h +81 -0
@@ -1393,6 +1393,86 @@ static void damon_test_commit_filter(struct kunit *test) }); } +static struct damon_ctx *damon_test_help_setup_probes (unsigned int weights[], +int nr_weights) +{ +struct damon_ctx *ctx; +struct damon_probe *probe; +int i; + + ctx =damon_new_ctx (); +if (!ctx) +return NULL ; +for (i =0 ; i < nr_weights; i++) { + probe =damon_new_probe (); +if (!probe) { +damon_destroy_ctx (ctx); +return NULL ; + } + probe->weight = weights[i]; +damon_add_probe (ctx, probe); + } +return ctx; +} + +static void damon_test_commit_probes_for (struct kunit *test, +unsigned int dst_weights[],int nr_dst_probes, +unsigned int src_weights[],int nr_src_probes) +{ +struct damon_ctx *dst, *src; +int err; +struct damon_probe *dst_probe, *src_probe; + + dst =damon_test_help_setup_probes (dst_weights, nr_dst_probes); +if (!dst) +kunit_skip (test,"dst alloc fail" ); + src =damon_test_help_setup_probes (src_weights, nr_src_probes); +if (!src) { +damon_destroy_ctx (dst); +kunit_skip (test,"src alloc fail" ); + } + + err =damon_commit_probes (dst, src); +KUNIT_EXPECT_EQ (test, err,0 ); +if (err) +return ; + nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) + nr_dst_probes++; + nr_src_probes =0 ; +damon_for_each_probe (src_probe, src) + nr_src_probes++; +KUNIT_EXPECT_EQ (test, nr_dst_probes, nr_src_probes); + nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) { + src_probe =damon_nth_probe (nr_dst_probes, src); +KUNIT_EXPECT_EQ (test, src_probe->weight, dst_probe->weight); + nr_dst_probes++; + } +damon_destroy_ctx (dst); +damon_destroy_ctx (src); +} + +static void damon_test_commit_probes (struct kunit *test) +{ +damon_test_commit_probes_for (test, + (unsigned int []){},0 , (unsigned int []){},0 ); +damon_test_commit_probes_for (test, + (unsigned int []){},0 , (unsigned int []){1 },1 ); +damon_test_commit_probes_for (test, + (unsigned int []){},0 , (unsigned int []){1 ,2 },2 ); +damon_test_commit_probes_for (test, + (unsigned int []){1 },1 , (unsigned int []){2 },1 ); +damon_test_commit_probes_for (test, + (unsigned int []){1 },1 , (unsigned int []){2 ,3 },2 ); +damon_test_commit_probes_for (test, + (unsigned int []){2 ,3 },2 , (unsigned int []){1 },1 ); +damon_test_commit_probes_for (test, + (unsigned int []){2 ,3 },2 , (unsigned int []){},0 ); +damon_test_commit_probes_for (test, + (unsigned int []){2 },1 , (unsigned int []){},0 ); +} +static void damon_test_commit_ctx (struct kunit *test) {struct damon_ctx *src, *dst;
@@ -1745,6 +1825,7 @@ static struct kunit_case damon_test_cases[] = {KUNIT_CASE (damos_test_commit_migrate_hot),KUNIT_CASE (damon_test_commit_target_regions),KUNIT_CASE (damon_test_commit_filter), +KUNIT_CASE (damon_test_commit_probes),KUNIT_CASE (damon_test_commit_ctx),KUNIT_CASE (damos_test_filter_out), KUNIT_CASE(damon_test_feed_loop_next_input),
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] Missing cleanup in the error path of `damon_test_commit_probes_for` causes a memory leak of…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Missing cleanup in the error path of damon_test_commit_probes_for causes a memory leak of dynamically allocated test structures.
- [Medium] Missing bounds check in damon_test_commit_probes_for can lead to a NULL pointer dereference when a test assertion fails. --
--- Patch [2]: [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test --- commit 490c9d2d6b4090811aaa428df3f6d9ce89e2d406
Author: SJ Park <[email protected]>
mm/damon/tests/core-kunit: add damon_commit_probes() test
Add kunit test to ensure damon_commit_probes() updates destination DAMON context with source probes as expected.
Quoted 4 lines
mm/damon/tests/core-kunit.h +0
-0
[ ... ]
Quoted 11 lines
mm/damon/tests/core-kunit.h +11
-0+static void damon_test_commit_probes_for (struct kunit *test, +unsigned int dst_weights[],int nr_dst_probes, +unsigned int src_weights[],int nr_src_probes) +{ +struct damon_ctx *dst, *src; +int err; +struct damon_probe *dst_probe, *src_probe; + + dst =damon_test_help_setup_probes (dst_weights, nr_dst_probes); +if (!dst) +kunit_skip (test,"dst alloc fail" );
mm/damon/tests/core-kunit.h static void damon_test_commit_filter(struct kunit *test) · line 1438
Quoted 10 lines
mm/damon/tests/core-kunit.h +10
-0+ src =damon_test_help_setup_probes (src_weights, nr_src_probes); +if (!src) { +damon_destroy_ctx (dst); +kunit_skip (test,"src alloc fail" ); + } + + err =damon_commit_probes (dst, src); +KUNIT_EXPECT_EQ (test, err,0 ); +if (err) +return ;
[Severity: Medium]
Does this error path leak the dst and src context structures?
If damon_commit_probes() returns an error, the early return here skips the cleanup calls to damon_destroy_ctx(dst) and damon_destroy_ctx(src) at the end of the function.
mm/damon/tests/core-kunit.h static void damon_test_commit_filter(struct kunit *test) · line 1449
Quoted 11 lines
mm/damon/tests/core-kunit.h +11
-0+ nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) + nr_dst_probes++; + nr_src_probes =0 ; +damon_for_each_probe (src_probe, src) + nr_src_probes++; +KUNIT_EXPECT_EQ (test, nr_dst_probes, nr_src_probes); + nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) { + src_probe =damon_nth_probe (nr_dst_probes, src); +KUNIT_EXPECT_EQ (test, src_probe->weight, dst_probe->weight);
[Severity: Medium]
Could this result in a NULL pointer dereference if the destination context ends up with more probes than the source context?
KUNIT_EXPECT_EQ() does not abort test execution if the previous check for nr_dst_probes == nr_src_probes fails. If dst has more probes, damon_nth_probe() will return NULL, and the next line accessing src_probe->weight will crash the test runner.
Quoted 5 lines
mm/damon/tests/core-kunit.h +5
-0+ nr_dst_probes++; + } +damon_destroy_ctx (dst); +damon_destroy_ctx (src); +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
SJ Park
maintainerRe: [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test
Quoted 46 lines · On Wed, 29 Jul 2026 15:00:27 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Missing cleanup in the error path ofdamon_test_commit_probes_forcauses a memory leak of dynamically allocated test structures.
- [Medium] Missing bounds check indamon_test_commit_probes_forcan lead to a NULL pointer dereference when a test assertion fails. ----- Patch [2]: [RFC PATCH 2/6]
mm/damon/tests/core-kunit: adddamon_commit_probes()test --- commit490c9d2d6b4090811aaa428df3f6d9ce89e2d406
Author: SJ Park <[email protected]>
mm/damon/tests/core-kunit: adddamon_commit_probes()testAdd kunit test to ensure
damon_commit_probes()updates destination DAMON context with source probes as expected.Quoted 4 lines
mm/damon/tests/core-kunit.h +0
-0[ ... ]
Quoted 11 lines
mm/damon/tests/core-kunit.h +11
-0+static void damon_test_commit_probes_for (struct kunit *test, +unsigned int dst_weights[],int nr_dst_probes, +unsigned int src_weights[],int nr_src_probes) +{ +struct damon_ctx *dst, *src; +int err; +struct damon_probe *dst_probe, *src_probe; + + dst =damon_test_help_setup_probes (dst_weights, nr_dst_probes); +if (!dst) +kunit_skip (test,"dst alloc fail" );mm/damon/tests/core-kunit.h static void damon_test_commit_filter(struct kunit *test) · line 1438
Quoted 10 lines
mm/damon/tests/core-kunit.h +10
-0+ src =damon_test_help_setup_probes (src_weights, nr_src_probes); +if (!src) { +damon_destroy_ctx (dst); +kunit_skip (test,"src alloc fail" ); + } + + err =damon_commit_probes (dst, src); +KUNIT_EXPECT_EQ (test, err,0 ); +if (err) +return ;[Severity: Medium]
Does this error path leak the dst and src context structures?
Quoted 3 lines
If
damon_commit_probes()returns an error, the early return here skips the cleanup calls todamon_destroy_ctx(dst)anddamon_destroy_ctx(src)at the end of the function.
Good catch, I will fix.
Quoted 17 lines
mm/damon/tests/core-kunit.h static void damon_test_commit_filter(struct kunit *test) · line 1449
Quoted 12 lines
mm/damon/tests/core-kunit.h +11
-0+ nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) + nr_dst_probes++; + nr_src_probes =0 ; +damon_for_each_probe (src_probe, src) + nr_src_probes++; +KUNIT_EXPECT_EQ (test, nr_dst_probes, nr_src_probes); + nr_dst_probes =0 ; +damon_for_each_probe (dst_probe, dst) { + src_probe =damon_nth_probe (nr_dst_probes, src); +KUNIT_EXPECT_EQ (test, src_probe->weight, dst_probe->weight);[Severity: Medium]
Could this result in a NULL pointer dereference if the destination context ends up with more probes than the source context?
Quoted 4 lines
KUNIT_EXPECT_EQ()does not abort test execution if the previous check fornr_dst_probes=nr_src_probesfails. If dst has more probes,damon_nth_probe()will return NULL, and the next line accessingsrc_probe->weightwill crash the test runner.
Good catch, I will fix.
Quoted 10 lines
Quoted 6 lines
mm/damon/tests/core-kunit.h +5
-0+ nr_dst_probes++; + } +damon_destroy_ctx (dst); +damon_destroy_ctx (src); +}Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Thanks,
SJ
SJ Park
maintainerRFC PATCH 3/6 selftests/damon/_damon_sysfs: implement DamonProbes
In reply to SJ ParkExtend _damon_sysfs.py to support staging and committing DAMON probes. It will be used for setting DAMON probes via sysfs changes for testing purposes.
--- tools/testing/selftests/damon/_damon_sysfs.py | 123 +++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-)
tools/testing/selftests/damon/_damon_sysfs.py +122 -1
@@ -558,6 +558,115 @@ class IntervalsGoal: return err return None +class DamonFilter: + type_ = None + matching = None + allow = None + filters = None + path = None + idx = None + + def __init__(self, type_='anon', matching=False, allow=False, path=None): + self.type_ = type_ + self.matching = matching + self.allow = allow + self.path = path + + def sysfs_dir(self): + return os.path.join(self.filters.sysfs_dir(), '%d' % self.idx) + + def stage(self): + err = write_file(os.path.join(self.sysfs_dir(), 'type'), self.type_) + if err is not None: + return err + err = write_file(os.path.join(self.sysfs_dir(), 'matching'), + 'Y' if self.matching else 'N') + if err is not None: + return err + err = write_file(os.path.join(self.sysfs_dir(), 'allow'), + 'Y' if self.allow else 'N') + if err is not None: + return err + if self.type_ == 'memcg': + err = write_file(os.path.join(self.sysfs_dir(), 'path'), self.path) + if err is not None: + return err + return None + +class DamonFilters: + filters = None + probe = None + + def __init__(self, filters=None): + if filters is None: + filters = [] + self.filters = filters + for idx, filter in enumerate(self.filters): + filter.filters = self + filter.idx = idx + + def sysfs_dir(self): + return os.path.join(self.probe.sysfs_dir(), 'filters') + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'nr_filters'), + len(self.filters)) + if err is not None: + return err + for filter in self.filters: + err = filter.stage() + if err is not None: + return err + return None + +class DamonProbe: + weight = None + filters = None + probes = None + idx = None + + def __init__(self, weight=0, filters=None): + self.weight = weight + if filters is None: + filters = DamonFilters() + self.filters = filters + self.filters.probe = self + + def sysfs_dir(self): + return os.path.join(self.probes.sysfs_dir(), '%d' % self.idx) + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'weight'), '%d' % self.weight) + return self.filters.stage() + +class DamonProbes: + probes = None + attrs = None + + def __init__(self, probes=None): + if probes is None: + probes = [] + self.probes = probes + for idx, probe in enumerate(self.probes): + probe.probes = self + probe.idx = idx + + def sysfs_dir(self): + return os.path.join(self.attrs.sysfs_dir(), 'probes') + + def stage(self): + err = write_file(os.path.join(self.sysfs_dir(), 'nr_probes'), + len(self.probes)) + if err is not None: + return err + for probe in self.probes: + err = probe.stage() + if err is not None: + return err + return None + class DamonAttrs: sample_us = None aggr_us = None
@@ -565,11 +674,12 @@ class DamonAttrs: update_us = None min_nr_regions = None max_nr_regions = None + probes = None context = None def __init__(self, sample_us=5000, aggr_us=100000, intervals_goal=IntervalsGoal(), update_us=1000000, - min_nr_regions=10, max_nr_regions=1000): + min_nr_regions=10, max_nr_regions=1000, probes=None): self.sample_us = sample_us self.aggr_us = aggr_us self.intervals_goal = intervals_goal
@@ -577,6 +687,10 @@ class DamonAttrs: self.update_us = update_us self.min_nr_regions = min_nr_regions self.max_nr_regions = max_nr_regions + if probes is None: + probes = DamonProbes() + self.probes = probes + self.probes.attrs = self def interval_sysfs_dir(self): return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs',
@@ -586,6 +700,9 @@ class DamonAttrs: return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs', 'nr_regions') + def sysfs_dir(self): + return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs') + def stage(self): err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'), self.sample_us)
@@ -615,6 +732,10 @@ class DamonAttrs: if err is not None: return err + err = self.probes.stage() + if err is not None: + return err + class DamonCtx: ops = None monitoring_attrs = None
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The error result of `write_file()` for setting the probe weight is silently discarded. --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The error result of write_file() for setting the probe weight is silently discarded. --
--- Patch [3]: [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes --- commit 12ef2c079bfc3ec5e9f25fc085e18c6bca931488
Author: SJ Park <[email protected]>
selftests/damon/_damon_sysfs: implement DamonProbes
Extend _damon_sysfs.py to support staging and committing DAMON probes. It will be used for setting DAMON probes via sysfs changes for testing purposes.
Quoted 3 lines
tools/testing/selftests/damon/_damon_sysfs.py +0
-0
[ ... ]
Quoted 10 lines
tools/testing/selftests/damon/_damon_sysfs.py +10
-0+class DamonProbe: + weight = None + filters = None + probes = None + idx = None + + def __init__(self, weight=0, filters=None): + self.weight = weight + if filters is None: + filters = DamonFilters()
tools/testing/selftests/damon/_damon_sysfs.py class IntervalsGoal: · line 642
Quoted 10 lines
tools/testing/selftests/damon/_damon_sysfs.py +10
-0+ self.filters = filters + self.filters.probe = self + + def sysfs_dir(self): + return os.path.join(self.probes.sysfs_dir(), '%d' % self.idx) + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'weight'), '%d' % self.weight) + return self.filters.stage()
[Severity: Medium]
Is err intentionally ignored here? If write_file() fails to write the weight to sysfs, it returns an error string. Returning self.filters.stage() directly without checking err will swallow the error and might cause tests to proceed with incorrect assumptions about the probe configuration.
Should this check err before returning, similar to how it is handled in other stage() methods?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
SJ Park
maintainerRe: [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes
Quoted 47 lines · On Wed, 29 Jul 2026 15:04:39 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The error result ofwrite_file()for setting the probe weight is silently discarded. ----- Patch [3]: [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes --- commit
12ef2c079bfc3ec5e9f25fc085e18c6bca931488
Author: SJ Park <[email protected]>selftests/damon/_damon_sysfs: implement DamonProbes
Extend
_damon_sysfs.pyto support staging and committing DAMON probes. It will be used for setting DAMON probes via sysfs changes for testing purposes.Quoted 3 lines
tools/testing/selftests/damon/_damon_sysfs.py +0
-0[ ... ]
Quoted 10 lines
tools/testing/selftests/damon/_damon_sysfs.py +10
-0+class DamonProbe: + weight = None + filters = None + probes = None + idx = None + + def __init__(self, weight=0, filters=None): + self.weight = weight + if filters is None: + filters = DamonFilters()tools/testing/selftests/damon/_damon_sysfs.py class IntervalsGoal: · line 642
Quoted 10 lines
tools/testing/selftests/damon/_damon_sysfs.py +10
-0+ self.filters = filters + self.filters.probe = self + + def sysfs_dir(self): + return os.path.join(self.probes.sysfs_dir(), '%d' % self.idx) + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'weight'), '%d' % self.weight) + return self.filters.stage()[Severity: Medium]
Is err intentionally ignored here? Ifwrite_file()fails to write the weight to sysfs, it returns an error string. Returningself.filters.stage()directly without checking err will swallow the error and might cause tests to proceed with incorrect assumptions about the probe configuration.
Quoted 2 lines
Should this check err before returning, similar to how it is handled in other
stage()methods?
Good catch, I will fix.
'
Quoted 4 lines
Signature · 2 lines
-- Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Thanks,
SJ
SJ Park
maintainerRFC PATCH 4/6 selftests/damon/drgn_dump_damon_status: dump probes
In reply to SJ ParkExtend drgn_dump_damon_status.py to dump damon_ctx->probes. It will be used to see if in-kernel DAMON status are changed as the user sets the probes via sysfs.
--- .../selftests/damon/drgn_dump_damon_status.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+)
tools/testing/selftests/damon/drgn_dump_damon_status.py +32 -0
@@ -48,6 +48,37 @@ def attrs_to_dict(attrs): ['max_nr_regions', int], ]) +def filter_to_dict(damon_filter): + filter_type_keyword = { + 0: 'anon', + 1: 'memcg', + } + dict_ = { + 'type': filter_type_keyword[int(damon_filter.type)], + 'matching': bool(damon_filter.matching), + 'allow': bool(damon_filter.allow), + } + type_ = dict_['type'] + if type_ == 'memcg': + dict_['memcg_id'] = int(damon_filter.memcg_id) + return dict_ + +def filters_to_list(filters): + return [filter_to_dict(f) + for f in list_for_each_entry( + 'struct damon_filter', filters.address_of_(), 'list')] + +def probe_to_dict(probe): + return to_dict(probe, [ + ['weight', int], + ['filters', filters_to_list], + ]) + +def probes_to_list(probes): + return [probe_to_dict(p) + for p in list_for_each_entry( + 'struct damon_probe', probes.address_of_(), 'list')] + def addr_range_to_dict(addr_range): return to_dict(addr_range, [ ['start', int],
@@ -199,6 +230,7 @@ def damon_ctx_to_dict(ctx): return to_dict(ctx, [ ['ops', ops_to_dict], ['attrs', attrs_to_dict], + ['probes', probes_to_list], ['adaptive_targets', targets_to_list], ['schemes', schemes_to_list], ['pause', bool],
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 5/6 selftests/damon/sysfs.py: extend commit assertion function for probes
In reply to SJ ParkExtend DAMON sysfs testing commit assertion helper function to check probes too.
--- tools/testing/selftests/damon/sysfs.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
tools/testing/selftests/damon/sysfs.py +19 -0
@@ -178,6 +178,24 @@ def assert_monitoring_attrs_committed(attrs, dump): assert_true(dump['max_nr_regions'] == attrs.max_nr_regions, 'max_nr_regions', dump) +def assert_damon_filters_committed(filters, dump): + assert_true(len(dump) == len(filters.filters), 'probe filters', dump) + for idx, damon_filter in enumerate(filters.filters): + filter_dump = dump[idx] + assert_true(filter_dump['type'] == damon_filter.type_, 'type', + filter_dump) + assert_true(filter_dump['matching'] == damon_filter.matching, + 'matching', filter_dump) + assert_true(filter_dump['allow'] == damon_filter.allow, 'allow', + filter_dump) + +def assert_probes_committed(probes, dump): + assert_true(len(dump) == len(probes.probes), 'probes length', dump) + for idx, probe in enumerate(probes.probes): + probe_dump = dump[idx] + assert_true(probe.weight == probe_dump['weight'], 'weight', probe_dump) + assert_damon_filters_committed(probe.filters, probe_dump['filters']) + def assert_monitoring_target_committed(target, dump): # target.pid is the pid "number", while dump['pid'] is 'struct pid' # pointer, and hence cannot be compared.
@@ -196,6 +214,7 @@ def assert_ctx_committed(ctx, dump): } assert_true(dump['ops']['id'] == ops_val[ctx.ops], 'ops_id', dump) assert_monitoring_attrs_committed(ctx.monitoring_attrs, dump['attrs']) + assert_probes_committed(ctx.monitoring_attrs.probes, dump['probes']) assert_monitoring_targets_committed(ctx.targets, dump['adaptive_targets']) assert_schemes_committed(ctx.schemes, dump['schemes']) assert_true(dump['pause'] == ctx.pause, 'pause', dump)
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 6/6 selftests/damon/sysfs.py: test damon probes
In reply to SJ ParkExtend sysfs.py to commit DAMON probes via sysfs, and see if it changed in-kernel DAMON status as expected using drgn.
--- tools/testing/selftests/damon/sysfs.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
tools/testing/selftests/damon/sysfs.py +15 -1
@@ -319,7 +319,21 @@ def main(): intervals_goal=_damon_sysfs.IntervalsGoal( access_bp=400, aggrs=3, min_sample_us=5000, max_sample_us=10000000), - update_us=2000000), + update_us=2000000, + probes=_damon_sysfs.DamonProbes( + probes=[_damon_sysfs.DamonProbe( + weight=42, + filters=_damon_sysfs.DamonFilters( + filters=[ + _damon_sysfs.DamonFilter( + type_='anon', + matching=True, + allow=True, + ), + ]), + ), + ]), + ), schemes=[_damon_sysfs.Damos( action='pageout', access_pattern=_damon_sysfs.DamosAccessPattern(
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] DamonProbe.stage() completely ignores the error returned when writing to the 'weight' sysfs…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] DamonProbe.stage() completely ignores the error returned when writing to the 'weight' sysfs file, masking potential write failures. --
--- Patch [6]: [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes --- commit e47c18c7c1e4b19237b2738bc5c072c3c570dcc9
Author: SJ Park <[email protected]>
selftests/damon/sysfs.py: test damon probes
This commit extends sysfs.py to test DAMON probes by committing them via sysfs and checking the in-kernel status using drgn.
tools/testing/selftests/damon/sysfs.py def main(): · line 325
Quoted 13 lines
tools/testing/selftests/damon/sysfs.py +4
-1@@ -319,7 +319,21 @@ def main(): intervals_goal=_damon_sysfs.IntervalsGoal( access_bp=400, aggrs=3, min_sample_us=5000, max_sample_us=10000000), - update_us=2000000), + update_us=2000000, + probes=_damon_sysfs.DamonProbes( + probes=[_damon_sysfs.DamonProbe( + weight=42,
[Severity: Medium]
Will this properly catch setup failures when setting the probe weight?
When testing DamonProbes, DamonProbe.stage() writes the weight to sysfs but overwrites the returned error status without checking it:
tools/testing/selftests/damon/_damon_sysfs.py:DamonProbe.stage()
def stage(self):
err = write_file(
os.path.join(self.sysfs_dir(), 'weight'), '%d' % self.weight)
return self.filters.stage()If the sysfs write fails, such as the kernel rejecting the weight value or the sysfs node being absent, the error is silently ignored. Could this cause the test suite to proceed as if setup succeeded, leading to false positive passes or confusing downstream errors?
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
SJ Park
maintainerRe: [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes
Quoted 40 lines · On Wed, 29 Jul 2026 15:19:33 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium]DamonProbe.stage()completely ignores the error returned when writing to the 'weight' sysfs file, masking potential write failures. ----- Patch [6]: [RFC PATCH 6/6]
selftests/damon/sysfs.py: test damon probes --- commite47c18c7c1e4b19237b2738bc5c072c3c570dcc9
Author: SJ Park <[email protected]>
selftests/damon/sysfs.py: test damon probesThis commit extends
sysfs.pyto test DAMON probes by committing them via sysfs and checking the in-kernel status using drgn.tools/testing/selftests/damon/sysfs.py def main(): · line 325
Quoted 13 lines
tools/testing/selftests/damon/sysfs.py +4
-1@@ -319,7 +319,21 @@ def main(): intervals_goal=_damon_sysfs.IntervalsGoal( access_bp@0, aggrs=3, min_sample_usP00, max_sample_us000000), - update_us 00000), + update_us 00000, + probes=_damon_sysfs.DamonProbes( + probes=[_damon_sysfs.DamonProbe( + weightB,[Severity: Medium]
Will this properly catch setup failures when setting the probe weight?When testing DamonProbes,
DamonProbe.stage()writes the weight to sysfs but overwrites the returned error status without checking it:tools/testing/selftests/damon/_damon_sysfs.py:DamonProbe.stage()
def stage(self): err = write_file( os.path.join(self.sysfs_dir(), 'weight'), '%d' % self.weight) return self.filters.stage()
Quoted 4 lines
If the sysfs write fails, such as the kernel rejecting the weight value or the sysfs node being absent, the error is silently ignored. Could this cause the test suite to proceed as if setup succeeded, leading to false positive passes or confusing downstream errors?
Yes, I will fix it.
Quoted 6 lines
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Thanks,
SJ