summaryrefslogtreecommitdiff
path: root/mm/damon/reclaim.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/damon/reclaim.c')
-rw-r--r--mm/damon/reclaim.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index ab974e477d2f..9bd341d62b4c 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -62,6 +62,36 @@ static struct damos_quota damon_reclaim_quota = {
};
DEFINE_DAMON_MODULES_DAMOS_QUOTAS(damon_reclaim_quota);
+/*
+ * Desired level of memory pressure-stall time in microseconds.
+ *
+ * While keeping the caps that set by other quotas, DAMON_RECLAIM automatically
+ * increases and decreases the effective level of the quota aiming this level of
+ * memory pressure is incurred. System-wide ``some`` memory PSI in microseconds
+ * per quota reset interval (``quota_reset_interval_ms``) is collected and
+ * compared to this value to see if the aim is satisfied. Value zero means
+ * disabling this auto-tuning feature.
+ *
+ * Disabled by default.
+ */
+static unsigned long quota_mem_pressure_us __read_mostly;
+module_param(quota_mem_pressure_us, ulong, 0600);
+
+/*
+ * User-specifiable feedback for auto-tuning of the effective quota.
+ *
+ * While keeping the caps that set by other quotas, DAMON_RECLAIM automatically
+ * increases and decreases the effective level of the quota aiming receiving this
+ * feedback of value ``10,000`` from the user. DAMON_RECLAIM assumes the feedback
+ * value and the quota are positively proportional. Value zero means disabling
+ * this auto-tuning feature.
+ *
+ * Disabled by default.
+ *
+ */
+static unsigned long quota_autotune_feedback __read_mostly;
+module_param(quota_autotune_feedback, ulong, 0600);
+
static struct damos_watermarks damon_reclaim_wmarks = {
.metric = DAMOS_WMARK_FREE_MEM_RATE,
.interval = 5000000, /* 5 seconds */
@@ -150,9 +180,22 @@ static struct damos *damon_reclaim_new_scheme(void)
&damon_reclaim_wmarks);
}
+static void damon_reclaim_copy_quota_status(struct damos_quota *dst,
+ struct damos_quota *src)
+{
+ dst->total_charged_sz = src->total_charged_sz;
+ dst->total_charged_ns = src->total_charged_ns;
+ dst->charged_sz = src->charged_sz;
+ dst->charged_from = src->charged_from;
+ dst->charge_target_from = src->charge_target_from;
+ dst->charge_addr_from = src->charge_addr_from;
+ dst->esz_bp = src->esz_bp;
+}
+
static int damon_reclaim_apply_parameters(void)
{
- struct damos *scheme;
+ struct damos *scheme, *old_scheme;
+ struct damos_quota_goal *goal;
struct damos_filter *filter;
int err = 0;
@@ -164,6 +207,32 @@ static int damon_reclaim_apply_parameters(void)
scheme = damon_reclaim_new_scheme();
if (!scheme)
return -ENOMEM;
+ if (!list_empty(&ctx->schemes)) {
+ damon_for_each_scheme(old_scheme, ctx)
+ damon_reclaim_copy_quota_status(&scheme->quota,
+ &old_scheme->quota);
+ }
+
+ if (quota_mem_pressure_us) {
+ goal = damos_new_quota_goal(DAMOS_QUOTA_SOME_MEM_PSI_US,
+ quota_mem_pressure_us);
+ if (!goal) {
+ damon_destroy_scheme(scheme);
+ return -ENOMEM;
+ }
+ damos_add_quota_goal(&scheme->quota, goal);
+ }
+
+ if (quota_autotune_feedback) {
+ goal = damos_new_quota_goal(DAMOS_QUOTA_USER_INPUT, 10000);
+ if (!goal) {
+ damon_destroy_scheme(scheme);
+ return -ENOMEM;
+ }
+ goal->current_value = quota_autotune_feedback;
+ damos_add_quota_goal(&scheme->quota, goal);
+ }
+
if (skip_anon) {
filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true);
if (!filter) {