Skip to contentSkip to conversation

mm/damon: improve/fixup/update ratio calculation, test and documentation

PATCH Applied SeongJae Park 2 participants 10 messages Mar 7 – Mar 9

Subsystems (5)
lore
Share & tools
lore

SeongJae Park

author maintainer
#0 lore raw

cover mm/damon: improve/fixup/update ratio calculation, test and documentation

Yet another batch of misc/minor improvements and fixups. Use mult_frac() instead of the worse open-coding for rate calculations (patch 1). Add a test for a previously found and fixed bug (patch 2). Improve and update comments and documentations for easier code review and up-to-date information (patches 3-6). Finally, fix an obvious typo (patch 7).

SeongJae Park (7):
mm/damon/core: use mult_frac() mm/damon/tests/core-kunit: add a test for damon_is_last_region() mm/damon/core: clarify damon_set_attrs() usages mm/damon: document non-zero length damon_region assumption Docs/admin-guide/mm/damn/lru_sort: fix intervals autotune parameter
name
Docs/mm/damon/maintainer-profile: use flexible review cadence Docs/mm/damon/index: fix typo: autoamted -> automated

 .../admin-guide/mm/damon/lru_sort.rst         |  4 +--
 Documentation/mm/damon/index.rst              |  2 +-
 Documentation/mm/damon/maintainer-profile.rst |  8 ++---
 include/linux/damon.h                         |  2 ++
 mm/damon/core.c                               | 32 ++++++++++++-------
 mm/damon/tests/core-kunit.h                   | 23 +++++++++++++
 6 files changed, 52 insertions(+), 19 deletions(-)

base-commit: fa1e30b2dede645519bf6743439d3925922651bc

Signature · 1 line
2.47.3
author maintainer
#1 lore raw

PATCH 1/7 mm/damon/core: use mult_frac()

There are multiple places in core code that do open-code rate calculations. Use mult_frac(), which is developed for doing that in a way more safe from overflow and precision loss.

---
 mm/damon/core.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
mm/damon/core.c +10 -10
index cd2d7a8e3fe92..4e931f7380477 100644
@@ -665,7 +665,7 @@ static unsigned int damon_accesses_bp_to_nr_accesses(
 static unsigned int damon_nr_accesses_to_accesses_bp(
 		unsigned int nr_accesses, struct damon_attrs *attrs)
 {
-	return nr_accesses * 10000 / damon_max_nr_accesses(attrs);
+	return mult_frac(nr_accesses, 10000, damon_max_nr_accesses(attrs));
 }
 
 static unsigned int damon_nr_accesses_for_new_attrs(unsigned int nr_accesses,
@@ -1722,7 +1722,7 @@ static unsigned long damon_get_intervals_score(struct damon_ctx *c)
 	}
 	target_access_events = max_access_events * goal_bp / 10000;
 	target_access_events = target_access_events ? : 1;
-	return access_events * 10000 / target_access_events;
+	return mult_frac(access_events, 10000, target_access_events);
 }
 
 static unsigned long damon_feed_loop_next_input(unsigned long last_input,
@@ -2202,7 +2202,7 @@ static __kernel_ulong_t damos_get_node_mem_bp(
 		numerator = i.totalram - i.freeram;
 	else	/* DAMOS_QUOTA_NODE_MEM_FREE_BP */
 		numerator = i.freeram;
-	return numerator * 10000 / i.totalram;
+	return mult_frac(numerator, 10000, i.totalram);
 }
 
 static unsigned long damos_get_node_memcg_used_bp(
@@ -2235,7 +2235,7 @@ static unsigned long damos_get_node_memcg_used_bp(
 		numerator = used_pages;
 	else	/* DAMOS_QUOTA_NODE_MEMCG_FREE_BP */
 		numerator = i.totalram - used_pages;
-	return numerator * 10000 / i.totalram;
+	return mult_frac(numerator, 10000, i.totalram);
 }
 #else
 static __kernel_ulong_t damos_get_node_mem_bp(
@@ -2265,8 +2265,8 @@ static unsigned int damos_get_in_active_mem_bp(bool active_ratio)
 		global_node_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
 	total = active + inactive;
 	if (active_ratio)
-		return active * 10000 / total;
-	return inactive * 10000 / total;
+		return mult_frac(active, 10000, total);
+	return mult_frac(inactive, 10000, total);
 }
 
 static void damos_set_quota_goal_current_value(struct damos_quota_goal *goal)
@@ -2309,8 +2309,8 @@ static unsigned long damos_quota_score(struct damos_quota *quota)
 	damos_for_each_quota_goal(goal, quota) {
 		damos_set_quota_goal_current_value(goal);
 		highest_score = max(highest_score,
-				goal->current_value * 10000 /
-				goal->target_value);
+				mult_frac(goal->current_value, 10000,
+					goal->target_value));
 	}
 
 	return highest_score;
@@ -2340,8 +2340,8 @@ static void damos_set_effective_quota(struct damos_quota *quota)
 
 	if (quota->ms) {
 		if (quota->total_charged_ns)
-			throughput = mult_frac(quota->total_charged_sz, 1000000,
-							quota->total_charged_ns);
+			throughput = mult_frac(quota->total_charged_sz,
+					1000000, quota->total_charged_ns);
 		else
 			throughput = PAGE_SIZE * 1024;
 		esz = min(throughput * quota->ms, esz);
Signature · 1 line
2.47.3
author maintainer
#2 lore raw

PATCH 2/7 mm/damon/tests/core-kunit: add a test for damon_is_last_region()

In reply to SeongJae Park

There was a bug [1] in damon_is_last_region(). Add a kunit test to not reintroduce the bug.

[1] https://lore.kernel.org/[email protected]/

---
 mm/damon/tests/core-kunit.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
mm/damon/tests/core-kunit.h +23 -0
index 2289f9e4610c0..e86d4f4fe261a 100644
@@ -1311,6 +1311,28 @@ static void damon_test_apply_min_nr_regions(struct kunit *test)
 	damon_test_apply_min_nr_regions_for(test, 10, 2, 10, 2, 5);
 }
 
+static void damon_test_is_last_region(struct kunit *test)
+{
+	struct damon_region *r;
+	struct damon_target *t;
+	int i;
+
+	t = damon_new_target();
+	if (!t)
+		kunit_skip(test, "target alloc fail\n");
+
+	for (i = 0; i < 4; i++) {
+		r = damon_new_region(i * 2, (i + 1) * 2);
+		if (!r) {
+			damon_free_target(t);
+			kunit_skip(test, "region alloc %d fail\n", i);
+		}
+		damon_add_region(r, t);
+		KUNIT_EXPECT_TRUE(test, damon_is_last_region(r, t));
+	}
+	damon_free_target(t);
+}
+
 static struct kunit_case damon_test_cases[] = {
 	KUNIT_CASE(damon_test_target),
 	KUNIT_CASE(damon_test_regions),
@@ -1339,6 +1361,7 @@ static struct kunit_case damon_test_cases[] = {
 	KUNIT_CASE(damon_test_feed_loop_next_input),
 	KUNIT_CASE(damon_test_set_filters_default_reject),
 	KUNIT_CASE(damon_test_apply_min_nr_regions),
+	KUNIT_CASE(damon_test_is_last_region),
 	{},
 };
 
Signature · 1 line
2.47.3
Tested-by Reviewed-by on v1 2/7
#3 lore raw

Re: [PATCH 2/7] mm/damon/tests/core-kunit: add a test for damon_is_last_region()

Quoted 6 lines

There was a bug [1] in damon_is_last_region(). Add a kunit test to not reintroduce the bug.

[1] https://lore.kernel.org/[email protected]/

Hi SeongJae,

I've been following the previous discussion regarding the bug in damon_is_last_region() where the arguments of list_is_last() were accidentally swapped.

I have verified this patch by running the KUnit tests on my arm64 native environment. The damon_test_is_last_region test case passed as expected, confirming that the fix is robust and the regression is effectively prevented.

--
Best Regards,
wang lian

author maintainer
#4 lore raw

PATCH 3/7 mm/damon/core: clarify damon_set_attrs() usages

In reply to SeongJae Park

damon_set_attrs() is called for multiple purposes from multiple places. Calling it in an unsafe context can make DAMON internal state polluted and results in unexpected behaviors. Clarify when it is safe, and where it is being called.

---
 mm/damon/core.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
mm/damon/core.c +10 -2
index 4e931f7380477..7f74982535aca 100644
@@ -751,8 +751,16 @@ static bool damon_valid_intervals_goal(struct damon_attrs *attrs)
  * @ctx:		monitoring context
  * @attrs:		monitoring attributes
  *
- * This function should be called while the kdamond is not running, an access
- * check results aggregation is not ongoing (e.g., from damon_call().
+ * This function updates monitoring results and next monitoring/damos operation
+ * schedules.  Because those are periodically updated by kdamond, this should
+ * be called from a safe contexts.  Such contexts include damon_ctx setup time
+ * while the kdamond is not yet started, and inside of kdamond_fn().
+ *
+ * In detail, all DAMON API callers directly call this function for initial
+ * setup of damon_ctx before calling damon_start().  Some of the API callers
+ * also indirectly call this function via damon_call() -> damon_commit() for
+ * online parameters updates.  Finally, kdamond_fn() itself use this for
+ * applying auto-tuned monitoring intervals.
  *
  * Every time interval is in micro-seconds.
  *
Signature · 1 line
2.47.3
author maintainer
#5 lore raw

PATCH 4/7 mm/damon: document non-zero length damon_region assumption

In reply to SeongJae Park

DAMON regions are assumed to always be non-zero length. There was a confusion [1] about it, probably due to lack of the documentation. Document it.

[1] https://lore.kernel.org/[email protected]/

---
 include/linux/damon.h | 2 ++
 1 file changed, 2 insertions(+)
include/linux/damon.h +2 -0
index 9a88cf8d152d8..6bd71546f7b20 100644
@@ -55,6 +55,8 @@ struct damon_size_range {
  * @list:		List head for siblings.
  * @age:		Age of this region.
  *
+ * For any use case, @ar should be non-zero positive size.
+ *
  * @nr_accesses is reset to zero for every &damon_attrs->aggr_interval and be
  * increased for every &damon_attrs->sample_interval if an access to the region
  * during the last sampling interval is found.  The update of this field should
Signature · 1 line
2.47.3
author maintainer
#6 lore raw

PATCH 5/7 Docs/admin-guide/mm/damn/lru_sort: fix intervals autotune parameter name

In reply to SeongJae Park

The section name should be the same as the parameter name. Fix it.

Fixes ed581147a417 ("Docs/admin-guide/mm/damon/lru_sort: document intervals autotuning")
---
 Documentation/admin-guide/mm/damon/lru_sort.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Documentation/admin-guide/mm/damon/lru_sort.rst +2 -2
index 20a8378d5a946..73980bacc3a02 100644
@@ -91,8 +91,8 @@ increases and decreases the effective level of the quota aiming the LRU
 
 Disabled by default.
 
-Auto-tune monitoring intervals
-------------------------------
+autotune_monitoring_intervals
+-----------------------------
 
 If this parameter is set as ``Y``, DAMON_LRU_SORT automatically tunes DAMON's
 sampling and aggregation intervals.  The auto-tuning aims to capture meaningful
Signature · 1 line
2.47.3
author maintainer
#7 lore raw

PATCH 6/7 Docs/mm/damon/maintainer-profile: use flexible review cadence

In reply to SeongJae Park

The document mentions the maitainer is working in the usual 9-5 fashion. The maintainer nowadays prefers working in a more flexible way. Update the document to avoid contributors having a wrong time expectation.

---
 Documentation/mm/damon/maintainer-profile.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Documentation/mm/damon/maintainer-profile.rst +4 -4
index 41b1d73b9bd7b..bcb9798a27a86 100644
@@ -63,10 +63,10 @@ management subsystem maintainer.
 Review cadence
 --------------
 
-The DAMON maintainer does the work on the usual work hour (09:00 to 17:00,
-Mon-Fri) in PT (Pacific Time).  The response to patches will occasionally be
-slow.  Do not hesitate to send a ping if you have not heard back within a week
-of sending a patch.
+The DAMON maintainer usually work in a flexible way, except early morning in PT
+(Pacific Time).  The response to patches will occasionally be slow.  Do not
+hesitate to send a ping if you have not heard back within a week of sending a
+patch.
 
 Mailing tool
 ------------
Signature · 1 line
2.47.3
author maintainer
#8 lore raw

PATCH 7/7 Docs/mm/damon/index: fix typo: autoamted -> automated

In reply to SeongJae Park

There is an obvious typo. Fix it (s/autoamted/automated/).

Fixes 32d11b320897 ("Docs/mm/damon/index: simplify the intro")
---
 Documentation/mm/damon/index.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/mm/damon/index.rst +1 -1
index 82f6c5eea49a7..318f6a7bfea47 100644
@@ -12,7 +12,7 @@ DAMON is a Linux kernel subsystem for efficient :ref:`data access monitoring
  - *light-weight* (for production online usages),
  - *scalable* (in terms of memory size),
  - *tunable* (for flexible usages), and
- - *autoamted* (for production operation without manual tunings).
+ - *automated* (for production operation without manual tunings).
 
 .. toctree::
    :maxdepth: 2
Signature · 1 line
2.47.3
Acked-by on the v1 series
#9 lore raw
In reply to SeongJae Park
Quoted 6 lines

Yet another batch of misc/minor improvements and fixups. Use mult_frac() instead of the worse open-coding for rate calculations (patch 1). Add a test for a previously found and fixed bug (patch 2). Improve and update comments and documentations for easier code review and up-to-date information (patches 3-6). Finally, fix an obvious typo (patch 7).

Hi SeongJae,

Thanks for the patches and the CC!

I've reviewed the entire series and conducted functional testing on my arm64 environment (native VM). All 28 KUnit tests passed successfully, including
the newly added damon_test_is_last_region.

--
Best Regards,
wang lian