[PATCH 2/2] mm/damon/core: add sysfs nodes to set last_nr_accesses weight

From: cuiyangpei
Date: Tue Nov 28 2023 - 02:35:30 EST


The date access frequency is cleared every time the aggregation
interval is reached. In order to refer to the past time access
frequency, the current access frequency can be calculated by
setting the weight of the last access frequency.

Signed-off-by: cuiyangpei <cuiyangpei@xxxxxxxxxx>
---
.../ABI/testing/sysfs-kernel-mm-damon | 6 ++++
include/linux/damon.h | 3 ++
mm/damon/core.c | 29 +++++++++++++++++
mm/damon/sysfs.c | 31 +++++++++++++++++++
4 files changed, 69 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
index 819534dcfb6c..8367e26bf4da 100644
--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
@@ -74,6 +74,12 @@ Description: Writing a keyword for a monitoring operations set ('vaddr' for
Note that only the operations sets that listed in
'avail_operations' file are valid inputs.

+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/last_nr_accesses_weight
+Date: Nov 2023
+Contact: Ping Xiong <xiongping1@xxxxxxxxxx>
+Description: Writing a value to this file sets last_nr_accesses weight
+ of the DAMON context. Reading this file returns the value.
+
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/sample_us
Date: Mar 2022
Contact: SeongJae Park <sj@xxxxxxxxxx>
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 6495513cc6de..71e67a9d0996 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -18,6 +18,8 @@
#define DAMON_MIN_REGION PAGE_SIZE
/* Max priority score for DAMON-based operation schemes */
#define DAMOS_MAX_SCORE (99)
+/* set last_nr_accesses weight */
+#define LAST_NR_ACCESSES_WEIGHT 0

#define MIN_RECORD_BUFFER_LEN 1024
#define MAX_RECORD_BUFFER_LEN (4 * 1024 * 1024)
@@ -522,6 +524,7 @@ struct damon_attrs {
unsigned long ops_update_interval;
unsigned long min_nr_regions;
unsigned long max_nr_regions;
+ unsigned int last_nr_accesses_weight;
};

/**
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 630077d95dc6..230afcceea22 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1142,6 +1142,34 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
}
}

+static unsigned int __calculate_nr_accesses(struct damon_ctx *c, struct damon_region *r)
+{
+ unsigned int rem_old, rem_new;
+ unsigned int res;
+ unsigned int weight = c->attrs.last_nr_accesses_weight;
+
+ res = div_u64_rem(r->nr_accesses, 100, &rem_new) * (100 - weight)
+ + div_u64_rem(r->last_nr_accesses, 100, &rem_old) * weight;
+
+ if (rem_new)
+ res += rem_new * (100 - weight) / 100;
+ if (rem_old)
+ res += rem_old * weight / 100;
+
+ return res;
+}
+
+static void kdamon_update_nr_accesses(struct damon_ctx *c)
+{
+ struct damon_target *t;
+ struct damon_region *r;
+
+ damon_for_each_target(t, c) {
+ damon_for_each_region(r, t)
+ r->nr_accesses = __calculate_nr_accesses(c, r);
+ }
+}
+
/*
* Merge two adjacent regions into one region
*/
@@ -1469,6 +1497,7 @@ static int kdamond_fn(void *data)
max_nr_accesses = ctx->ops.check_accesses(ctx);

if (ctx->passed_sample_intervals == next_aggregation_sis) {
+ kdamon_update_nr_accesses(ctx);
kdamond_merge_regions(ctx,
max_nr_accesses / 10,
sz_limit);
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index 7a7d41e609e3..2946b0e91ad8 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -544,6 +544,7 @@ struct damon_sysfs_attrs {
struct kobject kobj;
struct damon_sysfs_intervals *intervals;
struct damon_sysfs_ul_range *nr_regions_range;
+ unsigned int last_nr_accesses_weight;
};

static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
@@ -553,6 +554,7 @@ static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
if (!attrs)
return NULL;
attrs->kobj = (struct kobject){};
+ attrs->last_nr_accesses_weight = LAST_NR_ACCESSES_WEIGHT;
return attrs;
}

@@ -602,12 +604,40 @@ static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
kobject_put(&attrs->intervals->kobj);
}

+static ssize_t last_nr_accesses_weight_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_attrs *attrs = container_of(kobj,
+ struct damon_sysfs_attrs, kobj);
+
+ return sysfs_emit(buf, "%u\n", attrs->last_nr_accesses_weight);
+}
+
+static ssize_t last_nr_accesses_weight_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_attrs *attrs = container_of(kobj,
+ struct damon_sysfs_attrs, kobj);
+ int err = kstrtoint(buf, 0, &attrs->last_nr_accesses_weight);
+
+ if (err)
+ return -EINVAL;
+ if (attrs->last_nr_accesses_weight > 100)
+ return -EINVAL;
+
+ return count;
+}
+
static void damon_sysfs_attrs_release(struct kobject *kobj)
{
kfree(container_of(kobj, struct damon_sysfs_attrs, kobj));
}

+static struct kobj_attribute damon_sysfs_attrs_last_nr_accesses_weight_attr =
+ __ATTR_RW_MODE(last_nr_accesses_weight, 0600);
+
static struct attribute *damon_sysfs_attrs_attrs[] = {
+ &damon_sysfs_attrs_last_nr_accesses_weight_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(damon_sysfs_attrs);
@@ -1083,6 +1113,7 @@ static int damon_sysfs_set_attrs(struct damon_ctx *ctx,
.ops_update_interval = sys_intervals->update_us,
.min_nr_regions = sys_nr_regions->min,
.max_nr_regions = sys_nr_regions->max,
+ .last_nr_accesses_weight = sys_attrs->last_nr_accesses_weight,
};
return damon_set_attrs(ctx, &attrs);
}
--
2.43.0