2023-11-21 05:37:14

by SeongJae Park

[permalink] [raw]
Subject: [RFC PATCH 0/2] mm/damon: export DAMON symbols and add sample loadable modules

DAMON cannot be used from loadable modules since it is not exporting its
symbols. This makes use of DAMON unnecessarily tedious. For example,
we presented basic usge of DAMON at kernel summit 2021[1] by writing
simple loadable DAMON application modules in live. Because the time was
limited (10 minutes) and the coding was to be done step by step, we had
to make a downstream commit that exports DAMON symbols. There were
users asking why the source code is now not working. It was mainly due
to the absence of the symbols export patch on their tree, but also due
to the changed DAMON interfaces. There were also multiple users
requesting support of loadable modules for easier deployment.

There's no reason to avoid exporting DAMON symbols. However, it would
be better to have concrete use cases of the symbols in the tree
together, for better maintenance of the interface and the use cases.
The kernels summit 2021's live-coded modules could be used for the
purpose.

Expose DAMON API modules for supporting the minimum modules and and add
the kernel summit 2021's modules that updated for latest DAMON API under
the samples directory. We will keep update of the sample modules. For
exporting more symbols, requesters would be required to merge their
modules using it in the tree together, or updsate the sample modules to
use the newly-exporting symbols in reasonable and still simple ways.

[1] https://linuxplumbersconf.org/event/11/contributions/984/

SeongJae Park (2):
mm/damon/core: export symbols for supporting loadable modules
samples: add DAMON sample kernel modules

MAINTAINERS | 1 +
mm/damon/core.c | 10 ++++
samples/Kconfig | 2 +
samples/Makefile | 2 +
samples/damon/Kconfig | 30 ++++++++++
samples/damon/Makefile | 3 +
samples/damon/damon_sample_prcl.c | 98 +++++++++++++++++++++++++++++++
samples/damon/damon_sample_wsse.c | 80 +++++++++++++++++++++++++
8 files changed, 226 insertions(+)
create mode 100644 samples/damon/Kconfig
create mode 100644 samples/damon/Makefile
create mode 100644 samples/damon/damon_sample_prcl.c
create mode 100644 samples/damon/damon_sample_wsse.c


base-commit: 79cc930e5e3dc73c972d9e422b5e2ab3fe56dce5
--
2.34.1


2023-11-21 05:37:15

by SeongJae Park

[permalink] [raw]
Subject: [RFC PATCH 1/2] mm/damon/core: export symbols for supporting loadable modules

Expose DAMON core symbols for supporting minimum functionality from
loadable modules.

Signed-off-by: SeongJae Park <[email protected]>
---
mm/damon/core.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/mm/damon/core.c b/mm/damon/core.c
index c080a16f6bdd..8ab8c902b9e2 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -111,6 +111,7 @@ int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id)
mutex_unlock(&damon_ops_lock);
return err;
}
+EXPORT_SYMBOL(damon_select_ops);

/*
* Construct a damon_region struct
@@ -353,6 +354,7 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,

return scheme;
}
+EXPORT_SYMBOL(damon_new_scheme);

static void damos_set_next_apply_sis(struct damos *s, struct damon_ctx *ctx)
{
@@ -390,6 +392,7 @@ void damon_destroy_scheme(struct damos *s)
damon_del_scheme(s);
damon_free_scheme(s);
}
+EXPORT_SYMBOL(damon_destroy_scheme);

/*
* Construct a damon_target struct
@@ -411,11 +414,13 @@ struct damon_target *damon_new_target(void)

return t;
}
+EXPORT_SYMBOL(damon_new_target);

void damon_add_target(struct damon_ctx *ctx, struct damon_target *t)
{
list_add_tail(&t->list, &ctx->adaptive_targets);
}
+EXPORT_SYMBOL(damon_add_target);

bool damon_targets_empty(struct damon_ctx *ctx)
{
@@ -493,6 +498,7 @@ struct damon_ctx *damon_new_ctx(void)

return ctx;
}
+EXPORT_SYMBOL(damon_new_ctx);

static void damon_destroy_targets(struct damon_ctx *ctx)
{
@@ -518,6 +524,7 @@ void damon_destroy_ctx(struct damon_ctx *ctx)

kfree(ctx);
}
+EXPORT_SYMBOL(damon_destroy_ctx);

static unsigned int damon_age_for_new_attrs(unsigned int age,
struct damon_attrs *old_attrs, struct damon_attrs *new_attrs)
@@ -645,6 +652,7 @@ void damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes,
for (i = 0; i < nr_schemes; i++)
damon_add_scheme(ctx, schemes[i]);
}
+EXPORT_SYMBOL(damon_set_schemes);

/**
* damon_nr_running_ctxs() - Return number of currently running contexts.
@@ -748,6 +756,7 @@ int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive)

return err;
}
+EXPORT_SYMBOL(damon_start);

/*
* __damon_stop() - Stops monitoring of a given context.
@@ -791,6 +800,7 @@ int damon_stop(struct damon_ctx **ctxs, int nr_ctxs)
}
return err;
}
+EXPORT_SYMBOL(damon_stop);

/*
* Reset the aggregated monitoring results ('nr_accesses' of each region).
--
2.34.1

2023-11-21 05:37:27

by SeongJae Park

[permalink] [raw]
Subject: [RFC PATCH 2/2] samples: add DAMON sample kernel modules

Add sample DAMON application kernel modules that same to the example
kernel modules that presented at kernel summit 2021 with 10 minutes live
coding[1] but updated for the latest DAMON interface.

Specifically, add two sample modules, namely damon_sample_wsse and
damon_sample_prcl. 'damon_sample_wsse' receives a pid of a process to
monitor the access, monitors the access to the virtual address space of
the process, calculate estimated working set size, and repeatedly print
it on the kernel log. 'damon_sample_prcl' is similar to
'damon_sample_wsse', but find regions that not accessed and proactively
reclaim those using DAMOS.

[1] https://linuxplumbersconf.org/event/11/contributions/984/

Signed-off-by: SeongJae Park <[email protected]>
---
MAINTAINERS | 1 +
samples/Kconfig | 2 +
samples/Makefile | 2 +
samples/damon/Kconfig | 30 ++++++++++
samples/damon/Makefile | 3 +
samples/damon/damon_sample_prcl.c | 98 +++++++++++++++++++++++++++++++
samples/damon/damon_sample_wsse.c | 80 +++++++++++++++++++++++++
7 files changed, 216 insertions(+)
create mode 100644 samples/damon/Kconfig
create mode 100644 samples/damon/Makefile
create mode 100644 samples/damon/damon_sample_prcl.c
create mode 100644 samples/damon/damon_sample_wsse.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6eedc85a013b..3ee99307229a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5781,6 +5781,7 @@ F: Documentation/mm/damon/
F: include/linux/damon.h
F: include/trace/events/damon.h
F: mm/damon/
+F: samples/damon/
F: tools/testing/selftests/damon/

DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
diff --git a/samples/Kconfig b/samples/Kconfig
index b0ddf5f36738..1e3f1b33b3d8 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -287,6 +287,8 @@ config SAMPLE_KMEMLEAK

source "samples/rust/Kconfig"

+source "samples/damon/Kconfig"
+
endif # SAMPLES

config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index 0a551c2b33f4..ae863e7c5250 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -38,3 +38,5 @@ obj-$(CONFIG_SAMPLE_KMEMLEAK) += kmemleak/
obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight/
obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/
obj-$(CONFIG_SAMPLES_RUST) += rust/
+obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/
+obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/
diff --git a/samples/damon/Kconfig b/samples/damon/Kconfig
new file mode 100644
index 000000000000..459042ce5958
--- /dev/null
+++ b/samples/damon/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "DAMON Samples"
+
+config SAMPLE_DAMON_WSSE
+ tristate "DAMON sameple module for working set size estimation"
+ depends on DAMON && DAMON_VADDR
+ help
+ This builds DAMON sample module for working set size estimation.
+
+ The module receives pid of a process, monitor access to the virtual
+ address space of the process, calculate the estimated working set
+ size of the process, and repeatedly print the size on the kernel log.
+
+ If unsure, say N.
+
+config SAMPLE_DAMON_PRCL
+ tristate "DAMON sameple module for access-aware proactive reclamation"
+ depends on DAMON && DAMON_VADDR
+ help
+ This builds DAMON sample module for access-aware proactive
+ reclamation.
+
+ The module receives pid of a process, monitor access to the virtual
+ address space of the process, find memory regions that not accessed,
+ and proactively reclaim the regions.
+
+ If unsure, say N.
+
+endmenu
diff --git a/samples/damon/Makefile b/samples/damon/Makefile
new file mode 100644
index 000000000000..df102e8c2b7b
--- /dev/null
+++ b/samples/damon/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon_sample_wsse.o
+obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon_sample_prcl.o
diff --git a/samples/damon/damon_sample_prcl.c b/samples/damon/damon_sample_prcl.c
new file mode 100644
index 000000000000..962b3309e490
--- /dev/null
+++ b/samples/damon/damon_sample_prcl.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "damon_sample_prcl: " fmt
+
+#include <linux/damon.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+static int target_pid __read_mostly;
+module_param(target_pid, int, 0600);
+
+static struct damon_ctx *ctx;
+static struct pid *target_pidp;
+
+static int damon_sample_prcl_after_aggregate(struct damon_ctx *c)
+{
+ struct damon_target *t;
+
+ damon_for_each_target(t, c) {
+ struct damon_region *r;
+ unsigned long wss = 0;
+
+ damon_for_each_region(r, t) {
+ if (r->nr_accesses > 0)
+ wss += r->ar.end - r->ar.start;
+ }
+ pr_info("wss: %lu\n", wss);
+ }
+ return 0;
+}
+
+static int __init damon_sample_prcl_init(void)
+{
+ struct damon_target *target;
+ struct damos *scheme;
+
+ pr_info("Hello\n");
+
+ ctx = damon_new_ctx();
+ if (!ctx)
+ return -ENOMEM;
+ if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
+ damon_destroy_ctx(ctx);
+ return -EINVAL;
+ }
+
+ target = damon_new_target();
+ if (!target) {
+ damon_destroy_ctx(ctx);
+ return -ENOMEM;
+ }
+ damon_add_target(ctx, target);
+ target_pidp = find_get_pid(target_pid);
+ if (!target_pidp) {
+ damon_destroy_ctx(ctx);
+ return -EINVAL;
+ }
+ target->pid = target_pidp;
+
+ ctx->callback.after_aggregation = damon_sample_prcl_after_aggregate;
+
+ scheme = damon_new_scheme(
+ &(struct damos_access_pattern) {
+ .min_sz_region = PAGE_SIZE,
+ .max_sz_region = ULONG_MAX,
+ .min_nr_accesses = 0,
+ .max_nr_accesses = 0},
+ DAMOS_PAGEOUT,
+ 0,
+ &(struct damos_quota){},
+ &(struct damos_watermarks){});
+ if (!scheme) {
+ damon_destroy_ctx(ctx);
+ return -ENOMEM;
+ }
+ damon_set_schemes(ctx, &scheme, 1);
+
+ return damon_start(&ctx, 1, true);
+}
+
+static void __exit damon_sample_prcl_exit(void)
+{
+ pr_info("Goodbye\n");
+ if (ctx) {
+ damon_stop(&ctx, 1);
+ damon_destroy_ctx(ctx);
+ }
+ if (target_pidp)
+ put_pid(target_pidp);
+}
+
+module_init(damon_sample_prcl_init);
+module_exit(damon_sample_prcl_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SeongJae Park");
+MODULE_DESCRIPTION("DAMON sample module for proactive reclamation");
diff --git a/samples/damon/damon_sample_wsse.c b/samples/damon/damon_sample_wsse.c
new file mode 100644
index 000000000000..7bfbd2bf56aa
--- /dev/null
+++ b/samples/damon/damon_sample_wsse.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "damon_sample_wsse: " fmt
+
+#include <linux/damon.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+static int target_pid __read_mostly;
+module_param(target_pid, int, 0600);
+
+static struct damon_ctx *ctx;
+static struct pid *target_pidp;
+
+static int damon_sample_wsse_after_aggregate(struct damon_ctx *c)
+{
+ struct damon_target *t;
+
+ damon_for_each_target(t, c) {
+ struct damon_region *r;
+ unsigned long wss = 0;
+
+ damon_for_each_region(r, t) {
+ if (r->nr_accesses > 0)
+ wss += r->ar.end - r->ar.start;
+ }
+ pr_info("wss: %lu\n", wss);
+ }
+ return 0;
+}
+
+static int __init damon_sample_wsse_init(void)
+{
+ struct damon_target *target;
+
+ pr_info("Hello\n");
+
+ ctx = damon_new_ctx();
+ if (!ctx)
+ return -ENOMEM;
+ if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
+ damon_destroy_ctx(ctx);
+ return -EINVAL;
+ }
+
+ target = damon_new_target();
+ if (!target) {
+ damon_destroy_ctx(ctx);
+ return -ENOMEM;
+ }
+ damon_add_target(ctx, target);
+ target_pidp = find_get_pid(target_pid);
+ if (!target_pidp) {
+ damon_destroy_ctx(ctx);
+ return -EINVAL;
+ }
+ target->pid = target_pidp;
+
+ ctx->callback.after_aggregation = damon_sample_wsse_after_aggregate;
+ return damon_start(&ctx, 1, true);
+}
+
+static void __exit damon_sample_wsse_exit(void)
+{
+ pr_info("Goodbye\n");
+ if (ctx) {
+ damon_stop(&ctx, 1);
+ damon_destroy_ctx(ctx);
+ }
+ if (target_pidp)
+ put_pid(target_pidp);
+}
+
+module_init(damon_sample_wsse_init);
+module_exit(damon_sample_wsse_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SeongJae Park");
+MODULE_DESCRIPTION("DAMON sample module for working set size estimation");
--
2.34.1