DAMON development mailing list
 help / color / mirror / Atom feed
* [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights
@ 2026-07-29 14:47 SJ Park
  2026-07-29 14:47 ` [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() SJ Park
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Andrew Morton, Brendan Higgins, David Gow, Shuah Khan,
	damon, kunit-dev, linux-kernel, linux-kselftest, linux-mm

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
-- 
2.47.3

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter()
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 14:52   ` sashiko-bot
  2026-07-29 14:47 ` [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test SJ Park
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Andrew Morton, Brendan Higgins, David Gow, damon,
	kunit-dev, linux-kernel, linux-kselftest, linux-mm

Add kunit test to ensure damon_commit_filter() updates destination
filter as expected for valid inputs.

Signed-off-by: SJ Park <sj@kernel.org>
---
 mm/damon/tests/core-kunit.h | 40 +++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index c7bda8aadef3f..ff864402e9c75 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -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),
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
  2026-07-29 14:47 ` [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 15:00   ` sashiko-bot
  2026-07-29 14:47 ` [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes SJ Park
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Andrew Morton, Brendan Higgins, David Gow, damon,
	kunit-dev, linux-kernel, linux-kselftest, linux-mm

Add kunit test to ensure damon_commit_probes() updates destination DAMON
context with source probes as expected.

Signed-off-by: SJ Park <sj@kernel.org>
---
 mm/damon/tests/core-kunit.h | 81 +++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index ff864402e9c75..d1e8c612fea03 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -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),
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
  2026-07-29 14:47 ` [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() SJ Park
  2026-07-29 14:47 ` [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 15:04   ` sashiko-bot
  2026-07-29 14:47 ` [RFC PATCH 4/6] selftests/damon/drgn_dump_damon_status: dump probes SJ Park
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
	linux-mm

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.

Signed-off-by: SJ Park <sj@kernel.org>
---
 tools/testing/selftests/damon/_damon_sysfs.py | 123 +++++++++++++++++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/damon/_damon_sysfs.py b/tools/testing/selftests/damon/_damon_sysfs.py
index e6a2265d721e8..d6afb5b2f0a4a 100644
--- a/tools/testing/selftests/damon/_damon_sysfs.py
+++ b/tools/testing/selftests/damon/_damon_sysfs.py
@@ -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
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 4/6] selftests/damon/drgn_dump_damon_status: dump probes
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
                   ` (2 preceding siblings ...)
  2026-07-29 14:47 ` [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 14:47 ` [RFC PATCH 5/6] selftests/damon/sysfs.py: extend commit assertion function for probes SJ Park
  2026-07-29 14:47 ` [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes SJ Park
  5 siblings, 0 replies; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
	linux-mm

Extend 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.

Signed-off-by: SJ Park <sj@kernel.org>
---
 .../selftests/damon/drgn_dump_damon_status.py | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/tools/testing/selftests/damon/drgn_dump_damon_status.py b/tools/testing/selftests/damon/drgn_dump_damon_status.py
index 09552e91bc782..4622046fd0118 100755
--- a/tools/testing/selftests/damon/drgn_dump_damon_status.py
+++ b/tools/testing/selftests/damon/drgn_dump_damon_status.py
@@ -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],
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 5/6] selftests/damon/sysfs.py: extend commit assertion function for probes
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
                   ` (3 preceding siblings ...)
  2026-07-29 14:47 ` [RFC PATCH 4/6] selftests/damon/drgn_dump_damon_status: dump probes SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 14:47 ` [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes SJ Park
  5 siblings, 0 replies; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
	linux-mm

Extend DAMON sysfs testing commit assertion helper function to check
probes too.

Signed-off-by: SJ Park <sj@kernel.org>
---
 tools/testing/selftests/damon/sysfs.py | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
index 88a26422ff44c..159cbeac067f8 100755
--- a/tools/testing/selftests/damon/sysfs.py
+++ b/tools/testing/selftests/damon/sysfs.py
@@ -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)
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes
  2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
                   ` (4 preceding siblings ...)
  2026-07-29 14:47 ` [RFC PATCH 5/6] selftests/damon/sysfs.py: extend commit assertion function for probes SJ Park
@ 2026-07-29 14:47 ` SJ Park
  2026-07-29 15:19   ` sashiko-bot
  5 siblings, 1 reply; 11+ messages in thread
From: SJ Park @ 2026-07-29 14:47 UTC (permalink / raw)
  Cc: SJ Park, Shuah Khan, damon, linux-kernel, linux-kselftest,
	linux-mm

Extend sysfs.py to commit DAMON probes via sysfs, and see if it changed
in-kernel DAMON status as expected using drgn.

Signed-off-by: SJ Park <sj@kernel.org>
---
 tools/testing/selftests/damon/sysfs.py | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
index 159cbeac067f8..66c826189320d 100755
--- a/tools/testing/selftests/damon/sysfs.py
+++ b/tools/testing/selftests/damon/sysfs.py
@@ -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(
-- 
2.47.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter()
  2026-07-29 14:47 ` [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() SJ Park
@ 2026-07-29 14:52   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-29 14:52 UTC (permalink / raw)
  To: SJ Park; +Cc: damon

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 <sj@kernel.org>

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.

> diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
> index 4a536d41cdb2d..6cbe22accabfb 100644
> --- a/mm/damon/tests/core-kunit.h
> +++ b/mm/damon/tests/core-kunit.h
> @@ -1306,6 +1306,45 @@ static void damon_test_commit_target_regions(struct kunit *test)

[ ... ]

> +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.

> +	default:
> +		break;
> +	}
> +}
> +
> +static void damon_test_commit_filter(struct kunit *test)
> +{

[ ... ]

> +	damon_test_commit_filter_for(test, &dst,
> +			&(struct damon_filter){
> +			.type = DAMON_FILTER_TYPE_MEMCG,
> +			.matching = false,
> +			.allow = false,
> +			.memcg_id = 123,
> +			});
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729144738.90895-1-sj@kernel.org?part=1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test
  2026-07-29 14:47 ` [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test SJ Park
@ 2026-07-29 15:00   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-29 15:00 UTC (permalink / raw)
  To: SJ Park; +Cc: damon

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 <sj@kernel.org>

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.

> diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
> index 6cbe22accabfb..6577410ace3da 100644
> --- a/mm/damon/tests/core-kunit.h
> +++ b/mm/damon/tests/core-kunit.h

[ ... ]

> +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;

[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.

> +	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.

> +		nr_dst_probes++;
> +	}
> +	damon_destroy_ctx(dst);
> +	damon_destroy_ctx(src);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729144738.90895-1-sj@kernel.org?part=2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes
  2026-07-29 14:47 ` [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes SJ Park
@ 2026-07-29 15:04   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-29 15:04 UTC (permalink / raw)
  To: SJ Park; +Cc: damon

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 <sj@kernel.org>

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.

> diff --git a/tools/testing/selftests/damon/_damon_sysfs.py b/tools/testing/selftests/damon/_damon_sysfs.py
> --- a/tools/testing/selftests/damon/_damon_sysfs.py
> +++ b/tools/testing/selftests/damon/_damon_sysfs.py

[ ... ]

> +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()

[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?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729144738.90895-1-sj@kernel.org?part=3

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes
  2026-07-29 14:47 ` [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes SJ Park
@ 2026-07-29 15:19   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-29 15:19 UTC (permalink / raw)
  To: SJ Park; +Cc: damon

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 <sj@kernel.org>

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.

> diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
> index 8c2dfc5ed8e04..852b6887a75ce 100755
> --- a/tools/testing/selftests/damon/sysfs.py
> +++ b/tools/testing/selftests/damon/sysfs.py
> @@ -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?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260729144738.90895-1-sj@kernel.org?part=6

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-07-29 15:19 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 14:47 [RFC PATCH 0/6] mm/damon: add kunit and selftests for probes and probe weights SJ Park
2026-07-29 14:47 ` [RFC PATCH 1/6] mm/damon/tests/core-kunit: test damon_commit_filter() SJ Park
2026-07-29 14:52   ` sashiko-bot
2026-07-29 14:47 ` [RFC PATCH 2/6] mm/damon/tests/core-kunit: add damon_commit_probes() test SJ Park
2026-07-29 15:00   ` sashiko-bot
2026-07-29 14:47 ` [RFC PATCH 3/6] selftests/damon/_damon_sysfs: implement DamonProbes SJ Park
2026-07-29 15:04   ` sashiko-bot
2026-07-29 14:47 ` [RFC PATCH 4/6] selftests/damon/drgn_dump_damon_status: dump probes SJ Park
2026-07-29 14:47 ` [RFC PATCH 5/6] selftests/damon/sysfs.py: extend commit assertion function for probes SJ Park
2026-07-29 14:47 ` [RFC PATCH 6/6] selftests/damon/sysfs.py: test damon probes SJ Park
2026-07-29 15:19   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox