* [PATCH 1/9] mm/damon/core: implement goal-oriented feedback-driven quota auto-tuning
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 2/9] mm/damon/sysfs-schemes: implement files for scheme quota goals setup SeongJae Park
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: SeongJae Park, damon, linux-mm, linux-kernel
Users can effectively control the upper-limit aggressiveness of DAMOS
schemes using the quota feature. The quota provides best result under
the limit by prioritizing regions based on the access pattern. That
said, finding the best value, which could depend on dynamic
characteristics of the system and the workloads, is still challenging.
Implement a simple feedback-driven tuning mechanism and use it for
automatic tuning of DAMOS quota. The implementation allows users to
provide the feedback by setting a feedback score returning callback
function. Then DAMOS periodically calls the function back and adjusts
the quota based on the return value of the callback and current quota
value.
Note that the absolute-value based time/size quotas still work as the
maximum hard limits of the scheme's aggressiveness. The feedback-driven
auto-tuned quota is applied only if it is not exceeding the manually set
maximum limits. Same for the scheme-target access pattern and filters
like other features.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 19 ++++++++++++
mm/damon/core.c | 68 +++++++++++++++++++++++++++++++++++++------
2 files changed, 78 insertions(+), 9 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index ab2f17d9926b..508a262418a2 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -136,6 +136,8 @@ enum damos_action {
* @weight_nr_accesses: Weight of the region's nr_accesses for prioritization.
* @weight_age: Weight of the region's age for prioritization.
*
+ * @get_score: Feedback function for self-tuning quota.
+ *
* To avoid consuming too much CPU time or IO resources for applying the
* &struct damos->action to large memory, DAMON allows users to set time and/or
* size quotas. The quotas can be set by writing non-zero values to &ms and
@@ -153,6 +155,17 @@ enum damos_action {
* You could customize the prioritization logic by setting &weight_sz,
* &weight_nr_accesses, and &weight_age, because monitoring operations are
* encouraged to respect those.
+ *
+ * If @get_score function pointer is set, DAMON calls it back and get the
+ * return value of it for every @reset_interval. Then, DAMON adjusts the
+ * effective quota using the return value as a feedback score to the current
+ * quota, using its internal feedback loop algorithm.
+ *
+ * The feedback loop algorithem assumes the quota input and the feedback score
+ * output are in a positive proportional relationship, and the goal of the
+ * tuning is getting the feedback screo value of 10,000. If @ms and/or @sz are
+ * set together, those work as a hard limit quota. If neither @ms nor @sz are
+ * set, the mechanism starts from the quota of one byte.
*/
struct damos_quota {
unsigned long ms;
@@ -163,6 +176,9 @@ struct damos_quota {
unsigned int weight_nr_accesses;
unsigned int weight_age;
+ unsigned long (*get_score)(void *arg);
+ void *get_score_arg;
+
/* private: */
/* For throughput estimation */
unsigned long total_charged_sz;
@@ -179,6 +195,9 @@ struct damos_quota {
/* For prioritization */
unsigned long histogram[DAMOS_MAX_SCORE + 1];
unsigned int min_score;
+
+ /* For feedback loop */
+ unsigned long esz_bp;
};
/**
diff --git a/mm/damon/core.c b/mm/damon/core.c
index ce1562783e7e..f91715a58dc7 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1038,26 +1038,76 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
}
}
-/* Shouldn't be called if quota->ms and quota->sz are zero */
+/*
+ * damon_feed_loop_next_input() - get next input to achieve a target score.
+ * @last_input The last input.
+ * @score Current score that made with @last_input.
+ *
+ * Calculate next input to achieve the target score, based on the last input
+ * and current score. Assuming the input and the score are positively
+ * proportional, calculate how much compensation should be added to or
+ * subtracted from the last input as a proportion of the last input. Avoid
+ * next input always being zero by setting it non-zero always. In short form
+ * (assuming support of float and signed calculations), the algorithm is as
+ * below.
+ *
+ * next_input = max(last_input * ((goal - current) / goal + 1), 1)
+ *
+ * For simple implementation, we assume the target score is always 10,000. The
+ * caller should adjust @score for this.
+ *
+ * Returns next input that assumed to achieve the target score.
+ */
+static unsigned long damon_feed_loop_next_input(unsigned long last_input,
+ unsigned long score)
+{
+ const unsigned long goal = 10000;
+ unsigned long score_goal_diff = max(goal, score) - min(goal, score);
+ unsigned long score_goal_diff_bp = score_goal_diff * 10000 / goal;
+ unsigned long compensation = last_input * score_goal_diff_bp / 10000;
+ /* Set minimum input as 10000 to avoid compensation be zero */
+ const unsigned long min_input = 10000;
+
+ if (goal > score)
+ return last_input + compensation;
+ if (last_input > compensation + min_input)
+ return last_input - compensation;
+ return min_input;
+}
+
+/* Shouldn't be called if quota->ms, quota->sz, and quota->get_score unset */
static void damos_set_effective_quota(struct damos_quota *quota)
{
unsigned long throughput;
unsigned long esz;
- if (!quota->ms) {
+ if (!quota->ms && !quota->get_score) {
quota->esz = quota->sz;
return;
}
- if (quota->total_charged_ns)
- throughput = quota->total_charged_sz * 1000000 /
- quota->total_charged_ns;
- else
- throughput = PAGE_SIZE * 1024;
- esz = throughput * quota->ms;
+ if (quota->get_score) {
+ quota->esz_bp = damon_feed_loop_next_input(
+ max(quota->esz_bp, 10000UL),
+ quota->get_score(quota->get_score_arg));
+ esz = quota->esz_bp / 10000;
+ }
+
+ if (quota->ms) {
+ if (quota->total_charged_ns)
+ throughput = quota->total_charged_sz * 1000000 /
+ quota->total_charged_ns;
+ else
+ throughput = PAGE_SIZE * 1024;
+ if (quota->get_score)
+ esz = min(throughput * quota->ms, esz);
+ else
+ esz = throughput * quota->ms;
+ }
if (quota->sz && quota->sz < esz)
esz = quota->sz;
+
quota->esz = esz;
}
@@ -1069,7 +1119,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
unsigned long cumulated_sz;
unsigned int score, max_score = 0;
- if (!quota->ms && !quota->sz)
+ if (!quota->ms && !quota->sz && !quota->get_score)
return;
/* New charge window starts */
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 2/9] mm/damon/sysfs-schemes: implement files for scheme quota goals setup
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
2023-11-30 2:36 ` [PATCH 1/9] mm/damon/core: implement goal-oriented feedback-driven quota auto-tuning SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 3/9] mm/damon/sysfs-schemes: commit damos quota goals user input to DAMOS SeongJae Park
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: SeongJae Park, damon, linux-mm, linux-kernel
Implement DAMON sysfs directories and files for the goals of DAMOS
quota. Those allow users set multiple goals for their aim, with target
values. Users can further enter the current score value for each goal
as feedback for DAMOS.
Note that this commit is implementing only the basic file operations,
and not connecting the files with the DAMOS core logic. Hence writing
something to the files makes no real effect. The following commit will
connect the file operations and the core logic.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 224 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 221 insertions(+), 3 deletions(-)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index fe0fe2562000..e5531dbd4cf1 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -820,6 +820,203 @@ static const struct kobj_type damon_sysfs_watermarks_ktype = {
.default_groups = damon_sysfs_watermarks_groups,
};
+/*
+ * quota goal directory
+ */
+
+struct damos_sysfs_quota_goal {
+ struct kobject kobj;
+ unsigned long target_value;
+ unsigned long current_value;
+};
+
+static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)
+{
+ return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);
+}
+
+static ssize_t target_value_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
+ damos_sysfs_quota_goal, kobj);
+
+ return sysfs_emit(buf, "%lu\n", goal->target_value);
+}
+
+static ssize_t target_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
+ damos_sysfs_quota_goal, kobj);
+ int err = kstrtoul(buf, 0, &goal->target_value);
+
+ return err ? err : count;
+}
+
+static ssize_t current_value_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
+ damos_sysfs_quota_goal, kobj);
+
+ return sysfs_emit(buf, "%lu\n", goal->current_value);
+}
+
+static ssize_t current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
+ damos_sysfs_quota_goal, kobj);
+ int err = kstrtoul(buf, 0, &goal->current_value);
+
+ /* feed callback should check existence of this file and read value */
+ return err ? err : count;
+}
+
+static void damos_sysfs_quota_goal_release(struct kobject *kobj)
+{
+ /* or, notify this release to the feed callback */
+ kfree(container_of(kobj, struct damos_sysfs_quota_goal, kobj));
+}
+
+static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =
+ __ATTR_RW_MODE(target_value, 0600);
+
+static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =
+ __ATTR_RW_MODE(current_value, 0600);
+
+static struct attribute *damos_sysfs_quota_goal_attrs[] = {
+ &damos_sysfs_quota_goal_target_value_attr.attr,
+ &damos_sysfs_quota_goal_current_value_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damos_sysfs_quota_goal);
+
+static const struct kobj_type damos_sysfs_quota_goal_ktype = {
+ .release = damos_sysfs_quota_goal_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damos_sysfs_quota_goal_groups,
+};
+
+/*
+ * quota goals directory
+ */
+
+struct damos_sysfs_quota_goals {
+ struct kobject kobj;
+ struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */
+ int nr;
+};
+
+static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void)
+{
+ return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL);
+}
+
+static void damos_sysfs_quota_goals_rm_dirs(
+ struct damos_sysfs_quota_goals *goals)
+{
+ struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr;
+ int i;
+
+ for (i = 0; i < goals->nr; i++)
+ kobject_put(&goals_arr[i]->kobj);
+ goals->nr = 0;
+ kfree(goals_arr);
+ goals->goals_arr = NULL;
+}
+
+static int damos_sysfs_quota_goals_add_dirs(
+ struct damos_sysfs_quota_goals *goals, int nr_goals)
+{
+ struct damos_sysfs_quota_goal **goals_arr, *goal;
+ int err, i;
+
+ damos_sysfs_quota_goals_rm_dirs(goals);
+ if (!nr_goals)
+ return 0;
+
+ goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr),
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!goals_arr)
+ return -ENOMEM;
+ goals->goals_arr = goals_arr;
+
+ for (i = 0; i < nr_goals; i++) {
+ goal = damos_sysfs_quota_goal_alloc();
+ if (!goal) {
+ damos_sysfs_quota_goals_rm_dirs(goals);
+ return -ENOMEM;
+ }
+
+ err = kobject_init_and_add(&goal->kobj,
+ &damos_sysfs_quota_goal_ktype, &goals->kobj,
+ "%d", i);
+ if (err) {
+ kobject_put(&goal->kobj);
+ damos_sysfs_quota_goals_rm_dirs(goals);
+ return err;
+ }
+
+ goals_arr[i] = goal;
+ goals->nr++;
+ }
+ return 0;
+}
+
+static ssize_t nr_goals_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_quota_goals *goals = container_of(kobj,
+ struct damos_sysfs_quota_goals, kobj);
+
+ return sysfs_emit(buf, "%d\n", goals->nr);
+}
+
+static ssize_t nr_goals_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_quota_goals *goals;
+ int nr, err = kstrtoint(buf, 0, &nr);
+
+ if (err)
+ return err;
+ if (nr < 0)
+ return -EINVAL;
+
+ goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj);
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ err = damos_sysfs_quota_goals_add_dirs(goals, nr);
+ mutex_unlock(&damon_sysfs_lock);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static void damos_sysfs_quota_goals_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj));
+}
+
+static struct kobj_attribute damos_sysfs_quota_goals_nr_attr =
+ __ATTR_RW_MODE(nr_goals, 0600);
+
+static struct attribute *damos_sysfs_quota_goals_attrs[] = {
+ &damos_sysfs_quota_goals_nr_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damos_sysfs_quota_goals);
+
+static const struct kobj_type damos_sysfs_quota_goals_ktype = {
+ .release = damos_sysfs_quota_goals_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damos_sysfs_quota_goals_groups,
+};
+
/*
* scheme/weights directory
*/
@@ -938,6 +1135,7 @@ static const struct kobj_type damon_sysfs_weights_ktype = {
struct damon_sysfs_quotas {
struct kobject kobj;
struct damon_sysfs_weights *weights;
+ struct damos_sysfs_quota_goals *goals;
unsigned long ms;
unsigned long sz;
unsigned long reset_interval_ms;
@@ -951,6 +1149,7 @@ static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
{
struct damon_sysfs_weights *weights;
+ struct damos_sysfs_quota_goals *goals;
int err;
weights = damon_sysfs_weights_alloc(0, 0, 0);
@@ -959,16 +1158,35 @@ static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
"as->kobj, "weights");
- if (err)
+ if (err) {
kobject_put(&weights->kobj);
- else
- quotas->weights = weights;
+ return err;
+ }
+ quotas->weights = weights;
+
+ goals = damos_sysfs_quota_goals_alloc();
+ if (!goals) {
+ kobject_put(&weights->kobj);
+ return -ENOMEM;
+ }
+ err = kobject_init_and_add(&goals->kobj,
+ &damos_sysfs_quota_goals_ktype, "as->kobj,
+ "goals");
+ if (err) {
+ kobject_put(&weights->kobj);
+ kobject_put(&goals->kobj);
+ } else {
+ quotas->goals = goals;
+ }
+
return err;
}
static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
{
kobject_put("as->weights->kobj);
+ damos_sysfs_quota_goals_rm_dirs(quotas->goals);
+ kobject_put("as->goals->kobj);
}
static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 3/9] mm/damon/sysfs-schemes: commit damos quota goals user input to DAMOS
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
2023-11-30 2:36 ` [PATCH 1/9] mm/damon/core: implement goal-oriented feedback-driven quota auto-tuning SeongJae Park
2023-11-30 2:36 ` [PATCH 2/9] mm/damon/sysfs-schemes: implement files for scheme quota goals setup SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 4/9] mm/damon/sysfs-schemes: implement a command for scheme quota goals only commit SeongJae Park
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: SeongJae Park, damon, linux-mm, linux-kernel
Make DAMON sysfs interface to read the user inputs for DAMOS quota goals
and pass those to DAMOS, so that the users can use the quota auto-tuning
feature. It uses the DAMON sysfs interface's user input commit
mechanism, which applies all user inputs for initial starting of DAMON
and online input updates, which can be done by writing 'on' and 'commit'
to the kdamond's 'state' file, respectively. In other words, the user
should periodically write appropriate value to 'current_value' files and
'commit' command to the 'state' file. 'target_value' files could also
be similarly updated at any time.
Note that the interface is supporting multiple goals while the core
logic supports only one goal. DAMON sysfs interface passes only best
feedback among the given inputs, to avoid making DAMOS too aggressive.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index e5531dbd4cf1..a7917534ca19 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -1868,6 +1868,34 @@ static int damon_sysfs_set_scheme_filters(struct damos *scheme,
return 0;
}
+static unsigned long damos_sysfs_get_quota_score(void *arg)
+{
+ return (unsigned long)arg;
+}
+
+static void damos_sysfs_set_quota_score(
+ struct damos_sysfs_quota_goals *sysfs_goals,
+ struct damos_quota *quota)
+{
+ struct damos_sysfs_quota_goal *sysfs_goal;
+ int i;
+
+ quota->get_score = NULL;
+ quota->get_score_arg = (void *)0;
+ for (i = 0; i < sysfs_goals->nr; i++) {
+ sysfs_goal = sysfs_goals->goals_arr[i];
+ if (!sysfs_goal->target_value)
+ continue;
+
+ /* Higher score makes scheme less aggressive */
+ quota->get_score_arg = (void *)max(
+ (unsigned long)quota->get_score_arg,
+ sysfs_goal->current_value * 10000 /
+ sysfs_goal->target_value);
+ quota->get_score = damos_sysfs_get_quota_score;
+ }
+}
+
static struct damos *damon_sysfs_mk_scheme(
struct damon_sysfs_scheme *sysfs_scheme)
{
@@ -1905,6 +1933,8 @@ static struct damos *damon_sysfs_mk_scheme(
.low = sysfs_wmarks->low,
};
+ damos_sysfs_set_quota_score(sysfs_quotas->goals, "a);
+
scheme = damon_new_scheme(&pattern, sysfs_scheme->action,
sysfs_scheme->apply_interval_us, "a, &wmarks);
if (!scheme)
@@ -1945,6 +1975,8 @@ static void damon_sysfs_update_scheme(struct damos *scheme,
scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
scheme->quota.weight_age = sysfs_weights->age;
+ damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota);
+
scheme->wmarks.metric = sysfs_wmarks->metric;
scheme->wmarks.interval = sysfs_wmarks->interval_us;
scheme->wmarks.high = sysfs_wmarks->high;
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 4/9] mm/damon/sysfs-schemes: implement a command for scheme quota goals only commit
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (2 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 3/9] mm/damon/sysfs-schemes: commit damos quota goals user input to DAMOS SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 5/9] mm/damon/core-test: add a unit test for the feedback loop algorithm SeongJae Park
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: SeongJae Park, damon, linux-mm, linux-kernel
To update DAMOS quota goals, users need to enter 'commit' command to the
'state' file of the kdamond, which applies not only the goals but entire
inputs. It is inefficient. Implement yet another 'state' file input
command for reading and committing only the scheme quota goals, namely
'commit_schemes_quota_goals'.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-common.h | 3 +++
mm/damon/sysfs-schemes.c | 16 ++++++++++++++++
mm/damon/sysfs.c | 27 +++++++++++++++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/mm/damon/sysfs-common.h b/mm/damon/sysfs-common.h
index 5ff081226e28..4c37a166eb81 100644
--- a/mm/damon/sysfs-common.h
+++ b/mm/damon/sysfs-common.h
@@ -56,3 +56,6 @@ int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx);
int damon_sysfs_schemes_clear_regions(
struct damon_sysfs_schemes *sysfs_schemes,
struct damon_ctx *ctx);
+
+void damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
+ struct damon_ctx *ctx);
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index a7917534ca19..8dbaac6e5c2d 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -1896,6 +1896,22 @@ static void damos_sysfs_set_quota_score(
}
}
+void damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
+ struct damon_ctx *ctx)
+{
+ struct damos *scheme;
+ int i = 0;
+
+ damon_for_each_scheme(scheme, ctx) {
+ struct damon_sysfs_scheme *sysfs_scheme;
+
+ sysfs_scheme = sysfs_schemes->schemes_arr[i];
+ damos_sysfs_set_quota_score(sysfs_scheme->quotas->goals,
+ &scheme->quota);
+ i++;
+ }
+}
+
static struct damos *damon_sysfs_mk_scheme(
struct damon_sysfs_scheme *sysfs_scheme)
{
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 7472404456aa..1f891e18b4ee 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -994,6 +994,11 @@ enum damon_sysfs_cmd {
DAMON_SYSFS_CMD_OFF,
/* @DAMON_SYSFS_CMD_COMMIT: Update kdamond inputs. */
DAMON_SYSFS_CMD_COMMIT,
+ /*
+ * @DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS: Commit the quota goals
+ * to DAMON.
+ */
+ DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS,
/*
* @DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS: Update scheme stats sysfs
* files.
@@ -1025,6 +1030,7 @@ static const char * const damon_sysfs_cmd_strs[] = {
"on",
"off",
"commit",
+ "commit_schemes_quota_goals",
"update_schemes_stats",
"update_schemes_tried_bytes",
"update_schemes_tried_regions",
@@ -1351,6 +1357,24 @@ static int damon_sysfs_commit_input(struct damon_sysfs_kdamond *kdamond)
kdamond->contexts->contexts_arr[0]);
}
+static int damon_sysfs_commit_schemes_quota_goals(
+ struct damon_sysfs_kdamond *sysfs_kdamond)
+{
+ struct damon_ctx *ctx;
+ struct damon_sysfs_context *sysfs_ctx;
+
+ if (!damon_sysfs_kdamond_running(sysfs_kdamond))
+ return -EINVAL;
+ /* TODO: Support multiple contexts per kdamond */
+ if (sysfs_kdamond->contexts->nr != 1)
+ return -EINVAL;
+
+ ctx = sysfs_kdamond->damon_ctx;
+ sysfs_ctx = sysfs_kdamond->contexts->contexts_arr[0];
+ damos_sysfs_set_quota_scores(sysfs_ctx->schemes, ctx);
+ return 0;
+}
+
/*
* damon_sysfs_cmd_request_callback() - DAMON callback for handling requests.
* @c: The DAMON context of the callback.
@@ -1379,6 +1403,9 @@ static int damon_sysfs_cmd_request_callback(struct damon_ctx *c, bool active)
case DAMON_SYSFS_CMD_COMMIT:
err = damon_sysfs_commit_input(kdamond);
break;
+ case DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS:
+ err = damon_sysfs_commit_schemes_quota_goals(kdamond);
+ break;
case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES:
total_bytes_only = true;
fallthrough;
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 5/9] mm/damon/core-test: add a unit test for the feedback loop algorithm
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (3 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 4/9] mm/damon/sysfs-schemes: implement a command for scheme quota goals only commit SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 6/9] selftests/damon: test quota goals directory SeongJae Park
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton
Cc: SeongJae Park, Brendan Higgins, David Gow, damon, linux-mm,
kunit-dev, linux-kselftest, linux-kernel
Implement a simple kunit test for testing the behavior of the feedback
loop algorithm for the aim-oriented feedback-friven DAMOS aggressiveness
auto tuning.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/core-test.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/mm/damon/core-test.h b/mm/damon/core-test.h
index e6a01ea2ec54..6e5e9502d648 100644
--- a/mm/damon/core-test.h
+++ b/mm/damon/core-test.h
@@ -446,6 +446,37 @@ static void damos_test_filter_out(struct kunit *test)
damos_free_filter(f);
}
+static void damon_test_feed_loop_next_input(struct kunit *test)
+{
+ unsigned long last_input = 900000, current_score = 200;
+
+ /*
+ * If current score is lower than the goal, which is always 10,000
+ * (read the comment on damon_feed_loop_next_input()'s comment), next
+ * input should be higher than the last input.
+ */
+ KUNIT_EXPECT_GT(test,
+ damon_feed_loop_next_input(last_input, current_score),
+ last_input);
+
+ /*
+ * If current score is higher than the goal, next input should be lower
+ * than the last input.
+ */
+ current_score = 250000000;
+ KUNIT_EXPECT_LT(test,
+ damon_feed_loop_next_input(last_input, current_score),
+ last_input);
+
+ /*
+ * The next input depends on the distance between the current score and
+ * the goal
+ */
+ KUNIT_EXPECT_GT(test,
+ damon_feed_loop_next_input(last_input, 200),
+ damon_feed_loop_next_input(last_input, 2000));
+}
+
static struct kunit_case damon_test_cases[] = {
KUNIT_CASE(damon_test_target),
KUNIT_CASE(damon_test_regions),
@@ -461,6 +492,7 @@ static struct kunit_case damon_test_cases[] = {
KUNIT_CASE(damon_test_moving_sum),
KUNIT_CASE(damos_test_new_filter),
KUNIT_CASE(damos_test_filter_out),
+ KUNIT_CASE(damon_test_feed_loop_next_input),
{},
};
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 6/9] selftests/damon: test quota goals directory
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (4 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 5/9] mm/damon/core-test: add a unit test for the feedback loop algorithm SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 7/9] Docs/mm/damon/design: document DAMOS quota auto tuning SeongJae Park
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton
Cc: SeongJae Park, Shuah Khan, damon, linux-mm, linux-kselftest,
linux-kernel
Add DAMON selftests for testing creation/existence of quota goals
directories and files, and simple valid input writes.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
tools/testing/selftests/damon/sysfs.sh | 27 ++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/tools/testing/selftests/damon/sysfs.sh b/tools/testing/selftests/damon/sysfs.sh
index 56f0230a8b92..e9a976d296e2 100755
--- a/tools/testing/selftests/damon/sysfs.sh
+++ b/tools/testing/selftests/damon/sysfs.sh
@@ -150,6 +150,32 @@ test_weights()
ensure_file "$weights_dir/age_permil" "exist" "600"
}
+test_goal()
+{
+ goal_dir=$1
+ ensure_dir "$goal_dir" "exist"
+ ensure_file "$goal_dir/target_value" "exist" "600"
+ ensure_file "$goal_dir/current_value" "exist" "600"
+}
+
+test_goals()
+{
+ goals_dir=$1
+ ensure_dir "$goals_dir" "exist"
+ ensure_file "$goals_dir/nr_goals" "exist" "600"
+
+ ensure_write_succ "$goals_dir/nr_goals" "1" "valid input"
+ test_goal "$goals_dir/0"
+
+ ensure_write_succ "$goals_dir/nr_goals" "2" "valid input"
+ test_goal "$goals_dir/0"
+ test_goal "$goals_dir/1"
+
+ ensure_write_succ "$goals_dir/nr_goals" "0" "valid input"
+ ensure_dir "$goals_dir/0" "not_exist"
+ ensure_dir "$goals_dir/1" "not_exist"
+}
+
test_quotas()
{
quotas_dir=$1
@@ -158,6 +184,7 @@ test_quotas()
ensure_file "$quotas_dir/bytes" "exist" 600
ensure_file "$quotas_dir/reset_interval_ms" "exist" 600
test_weights "$quotas_dir/weights"
+ test_goals "$quotas_dir/goals"
}
test_access_pattern()
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 7/9] Docs/mm/damon/design: document DAMOS quota auto tuning
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (5 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 6/9] selftests/damon: test quota goals directory SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 8/9] Docs/ABI/damon: document DAMOS quota goals SeongJae Park
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton
Cc: SeongJae Park, Jonathan Corbet, damon, linux-mm, linux-doc, linux-kernel
Document the DAMOS quota auto tuning feature on the design document.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/mm/damon/design.rst | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index 1f7e0586b5fa..947c9df6cd33 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -346,6 +346,17 @@ the weight will be respected are up to the underlying prioritization mechanism
implementation.
+Aim-oriented Feedback-driven Auto-tuning
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Automatic feedback-driven quota tuning. Instead of setting the absolute quota
+value, users can repeatedly provide numbers representing how much of their goal
+for the scheme is achieved as feedback. DAMOS then automatically tunes the
+aggressiveness (the quota) of the corresponding scheme. For example, if DAMOS
+is under achieving the goal, DAMOS automatically increases the quota. If DAMOS
+is over achieving the goal, it decreases the quota.
+
+
.. _damon_design_damos_watermarks:
Watermarks
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 8/9] Docs/ABI/damon: document DAMOS quota goals
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (6 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 7/9] Docs/mm/damon/design: document DAMOS quota auto tuning SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 2:36 ` [PATCH 9/9] Docs/admin-guide/mm/damon/usage: document for " SeongJae Park
2023-11-30 22:22 ` [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS Andrew Morton
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton
Cc: SeongJae Park, Jonathan Corbet, damon, linux-mm, linux-doc, linux-kernel
Update DAMON ABI document for the newly added DAMON sysfs files and
inputs for DAMOS quota goals.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
.../ABI/testing/sysfs-kernel-mm-damon | 33 +++++++++++++++----
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
index b35649a46a2f..bfa5b8288d8d 100644
--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
@@ -25,12 +25,14 @@ Description: Writing 'on' or 'off' to this file makes the kdamond starts or
stops, respectively. Reading the file returns the keywords
based on the current status. Writing 'commit' to this file
makes the kdamond reads the user inputs in the sysfs files
- except 'state' again. Writing 'update_schemes_stats' to the
- file updates contents of schemes stats files of the kdamond.
- Writing 'update_schemes_tried_regions' to the file updates
- contents of 'tried_regions' directory of every scheme directory
- of this kdamond. Writing 'update_schemes_tried_bytes' to the
- file updates only '.../tried_regions/total_bytes' files of this
+ except 'state' again. Writing 'commit_schemes_quota_goals' to
+ this file makes the kdamond reads the quota goal files again.
+ Writing 'update_schemes_stats' to the file updates contents of
+ schemes stats files of the kdamond. Writing
+ 'update_schemes_tried_regions' to the file updates contents of
+ 'tried_regions' directory of every scheme directory of this
+ kdamond. Writing 'update_schemes_tried_bytes' to the file
+ updates only '.../tried_regions/total_bytes' files of this
kdamond. Writing 'clear_schemes_tried_regions' to the file
removes contents of the 'tried_regions' directory.
@@ -212,6 +214,25 @@ Contact: SeongJae Park <sj@kernel.org>
Description: Writing to and reading from this file sets and gets the quotas
charge reset interval of the scheme in milliseconds.
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/nr_goals
+Date: Nov 2023
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing a number 'N' to this file creates the number of
+ directories for setting automatic tuning of the scheme's
+ aggressiveness named '0' to 'N-1' under the goals/ directory.
+
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/target_value
+Date: Nov 2023
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing to and reading from this file sets and gets the target
+ value of the goal metric.
+
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/current_value
+Date: Nov 2023
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing to and reading from this file sets and gets the current
+ value of the goal metric.
+
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/weights/sz_permil
Date: Mar 2022
Contact: SeongJae Park <sj@kernel.org>
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 9/9] Docs/admin-guide/mm/damon/usage: document for quota goals
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (7 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 8/9] Docs/ABI/damon: document DAMOS quota goals SeongJae Park
@ 2023-11-30 2:36 ` SeongJae Park
2023-11-30 22:22 ` [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS Andrew Morton
9 siblings, 0 replies; 11+ messages in thread
From: SeongJae Park @ 2023-11-30 2:36 UTC (permalink / raw)
To: Andrew Morton
Cc: SeongJae Park, Jonathan Corbet, damon, linux-mm, linux-doc, linux-kernel
Update DAMON sysfs usage for newly added DAMOS quota goals interface.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 48 +++++++++++++++++---
Documentation/mm/damon/design.rst | 2 +
2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index da94feb97ed1..ff9f62e65722 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -83,6 +83,8 @@ comma (","). ::
│ │ │ │ │ │ │ │ age/min,max
│ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
│ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
+ │ │ │ │ │ │ │ │ goals/nr_goals
+ │ │ │ │ │ │ │ │ │ 0/target_value,current_value
│ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
│ │ │ │ │ │ │ filters/nr_filters
│ │ │ │ │ │ │ │ 0/type,matching,memcg_id
@@ -113,6 +115,8 @@ details) exists. In the beginning, this directory has only one file,
child directories named ``0`` to ``N-1``. Each directory represents each
kdamond.
+.. _sysfs_kdamond:
+
kdamonds/<N>/
-------------
@@ -121,11 +125,18 @@ In each kdamond directory, two files (``state`` and ``pid``) and one directory
Reading ``state`` returns ``on`` if the kdamond is currently running, or
``off`` if it is not running. Writing ``on`` or ``off`` makes the kdamond be
-in the state. Writing ``commit`` to the ``state`` file makes kdamond reads the
+in the state.
+
+Writing ``commit`` to the ``state`` file makes kdamond reads the
user inputs in the sysfs files except ``state`` file again. Writing
-``update_schemes_stats`` to ``state`` file updates the contents of stats files
-for each DAMON-based operation scheme of the kdamond. For details of the
-stats, please refer to :ref:`stats section <sysfs_schemes_stats>`.
+``commit_schemes_quota_goals`` to the ``state`` file makes kdamond reads the
+DAMON-based operation schemes' :ref:`quota goals <sysfs_schemes_quota_goals>`
+of the kdamond.
+
+Writing ``update_schemes_stats`` to ``state`` file updates the
+contents of stats files for each DAMON-based operation scheme of the kdamond.
+For details of the stats, please refer to :ref:`stats section
+<sysfs_schemes_stats>`.
Writing ``update_schemes_tried_regions`` to ``state`` file updates the
DAMON-based operation scheme action tried regions directory for each
@@ -319,8 +330,7 @@ The directory for the :ref:`quotas <damon_design_damos_quotas>` of the given
DAMON-based operation scheme.
Under ``quotas`` directory, three files (``ms``, ``bytes``,
-``reset_interval_ms``) and one directory (``weights``) having three files
-(``sz_permil``, ``nr_accesses_permil``, and ``age_permil``) in it exist.
+``reset_interval_ms``) and two directores (``weights`` and ``goals``) exist.
You can set the ``time quota`` in milliseconds, ``size quota`` in bytes, and
``reset interval`` in milliseconds by writing the values to the three files,
@@ -330,11 +340,35 @@ apply the action to only up to ``bytes`` bytes of memory regions within the
``reset_interval_ms``. Setting both ``ms`` and ``bytes`` zero disables the
quota limits.
-You can also set the :ref:`prioritization weights
+Under ``weights`` directory, three files (``sz_permil``,
+``nr_accesses_permil``, and ``age_permil``) exist.
+You can set the :ref:`prioritization weights
<damon_design_damos_quotas_prioritization>` for size, access frequency, and age
in per-thousand unit by writing the values to the three files under the
``weights`` directory.
+.. _sysfs_schemes_quota_goals:
+
+schemes/<N>/quotas/goals/
+-------------------------
+
+The directory for the :ref:`automatic quota tuning goals
+<damon_design_damos_quotas_auto_tuning>` of the given DAMON-based operation
+scheme.
+
+In the beginning, this directory has only one file, ``nr_goals``. Writing a
+number (``N``) to the file creates the number of child directories named ``0``
+to ``N-1``. Each directory represents each goal and current achievement.
+Among the multiple feedback, the best one is used.
+
+Each goal directory contains two files, namely ``target_value`` and
+``current_value``. Users can set and get any number to those files to set the
+feedback. User space main workload's latency or throughput, system metrics
+like free memory ratio or memory pressure stall time (PSI) could be example
+metrics for the values. Note that users should write
+``commit_schemes_quota_goals`` to the ``state`` file of the :ref:`kdamond
+directory <sysfs_kdamond>` to pass the feedback to DAMON.
+
schemes/<N>/watermarks/
-----------------------
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index 947c9df6cd33..8b4a49ac057d 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -346,6 +346,8 @@ the weight will be respected are up to the underlying prioritization mechanism
implementation.
+.. _damon_design_damos_quotas_auto_tuning:
+
Aim-oriented Feedback-driven Auto-tuning
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS
2023-11-30 2:36 [PATCH 0/9] mm/damon: let users feed and tame/auto-tune DAMOS SeongJae Park
` (8 preceding siblings ...)
2023-11-30 2:36 ` [PATCH 9/9] Docs/admin-guide/mm/damon/usage: document for " SeongJae Park
@ 2023-11-30 22:22 ` Andrew Morton
9 siblings, 0 replies; 11+ messages in thread
From: Andrew Morton @ 2023-11-30 22:22 UTC (permalink / raw)
To: SeongJae Park
Cc: Jonathan Corbet, Shuah Khan, Brendan Higgins, David Gow, damon,
linux-mm, linux-doc, kunit-dev, linux-kselftest, linux-kernel
On Thu, 30 Nov 2023 02:36:43 +0000 SeongJae Park <sj@kernel.org> wrote:
> The core logic uses the below simple feedback loop algorithm to
> calculate the next aggressiveness level of the scheme from the current
> aggressiveness level and the current feedback (target_score and
> current_score). It calculates the compensation for next aggressiveness
> as a proportion of current aggressiveness and distance to the target
> score. As a result, it arrives at the near-goal state in a short time
> using big steps when it's far from the goal, but avoids making
> unnecessarily radical changes that could turn out to be a bad decision
> using small steps when its near to the goal.
fwiw, the above is a "proportional controller". MGLRU has, in
vmscan.c, a PID controller (proportional, integral, derivative). PID
controllers have better accuracy (the integral feedback) and better
stability (the derivative feedback).
Generalizing MGLRU's PID controller might be somewhat challenging!
^ permalink raw reply [flat|nested] 11+ messages in thread