12aca2546SSeongJae Park // SPDX-License-Identifier: GPL-2.0
22aca2546SSeongJae Park /*
32aca2546SSeongJae Park * proactive reclamation: monitor access pattern of a given process, find
4*1477b8cdSEnze Li * regions that seems not accessed, and proactively page out the regions.
52aca2546SSeongJae Park */
62aca2546SSeongJae Park
72aca2546SSeongJae Park #define pr_fmt(fmt) "damon_sample_prcl: " fmt
82aca2546SSeongJae Park
92aca2546SSeongJae Park #include <linux/damon.h>
102aca2546SSeongJae Park #include <linux/init.h>
112aca2546SSeongJae Park #include <linux/kernel.h>
122aca2546SSeongJae Park #include <linux/module.h>
132aca2546SSeongJae Park
142aca2546SSeongJae Park static int target_pid __read_mostly;
152aca2546SSeongJae Park module_param(target_pid, int, 0600);
162aca2546SSeongJae Park
172aca2546SSeongJae Park static int damon_sample_prcl_enable_store(
182aca2546SSeongJae Park const char *val, const struct kernel_param *kp);
192aca2546SSeongJae Park
202aca2546SSeongJae Park static const struct kernel_param_ops enable_param_ops = {
212aca2546SSeongJae Park .set = damon_sample_prcl_enable_store,
222aca2546SSeongJae Park .get = param_get_bool,
232aca2546SSeongJae Park };
242aca2546SSeongJae Park
252aca2546SSeongJae Park static bool enable __read_mostly;
262aca2546SSeongJae Park module_param_cb(enable, &enable_param_ops, &enable, 0600);
272aca2546SSeongJae Park MODULE_PARM_DESC(enable, "Enable of disable DAMON_SAMPLE_WSSE");
282aca2546SSeongJae Park
292aca2546SSeongJae Park static struct damon_ctx *ctx;
302aca2546SSeongJae Park static struct pid *target_pidp;
312aca2546SSeongJae Park
damon_sample_prcl_after_aggregate(struct damon_ctx * c)322aca2546SSeongJae Park static int damon_sample_prcl_after_aggregate(struct damon_ctx *c)
332aca2546SSeongJae Park {
342aca2546SSeongJae Park struct damon_target *t;
352aca2546SSeongJae Park
362aca2546SSeongJae Park damon_for_each_target(t, c) {
372aca2546SSeongJae Park struct damon_region *r;
382aca2546SSeongJae Park unsigned long wss = 0;
392aca2546SSeongJae Park
402aca2546SSeongJae Park damon_for_each_region(r, t) {
412aca2546SSeongJae Park if (r->nr_accesses > 0)
422aca2546SSeongJae Park wss += r->ar.end - r->ar.start;
432aca2546SSeongJae Park }
442aca2546SSeongJae Park pr_info("wss: %lu\n", wss);
452aca2546SSeongJae Park }
462aca2546SSeongJae Park return 0;
472aca2546SSeongJae Park }
482aca2546SSeongJae Park
damon_sample_prcl_start(void)492aca2546SSeongJae Park static int damon_sample_prcl_start(void)
502aca2546SSeongJae Park {
512aca2546SSeongJae Park struct damon_target *target;
5215e01f39SSeongJae Park struct damos *scheme;
532aca2546SSeongJae Park
542aca2546SSeongJae Park pr_info("start\n");
552aca2546SSeongJae Park
562aca2546SSeongJae Park ctx = damon_new_ctx();
572aca2546SSeongJae Park if (!ctx)
582aca2546SSeongJae Park return -ENOMEM;
592aca2546SSeongJae Park if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
602aca2546SSeongJae Park damon_destroy_ctx(ctx);
612aca2546SSeongJae Park return -EINVAL;
622aca2546SSeongJae Park }
632aca2546SSeongJae Park
642aca2546SSeongJae Park target = damon_new_target();
652aca2546SSeongJae Park if (!target) {
662aca2546SSeongJae Park damon_destroy_ctx(ctx);
672aca2546SSeongJae Park return -ENOMEM;
682aca2546SSeongJae Park }
692aca2546SSeongJae Park damon_add_target(ctx, target);
702aca2546SSeongJae Park target_pidp = find_get_pid(target_pid);
712aca2546SSeongJae Park if (!target_pidp) {
722aca2546SSeongJae Park damon_destroy_ctx(ctx);
732aca2546SSeongJae Park return -EINVAL;
742aca2546SSeongJae Park }
752aca2546SSeongJae Park target->pid = target_pidp;
762aca2546SSeongJae Park
772aca2546SSeongJae Park ctx->callback.after_aggregation = damon_sample_prcl_after_aggregate;
782aca2546SSeongJae Park
7915e01f39SSeongJae Park scheme = damon_new_scheme(
8015e01f39SSeongJae Park &(struct damos_access_pattern) {
8115e01f39SSeongJae Park .min_sz_region = PAGE_SIZE,
8215e01f39SSeongJae Park .max_sz_region = ULONG_MAX,
8315e01f39SSeongJae Park .min_nr_accesses = 0,
8415e01f39SSeongJae Park .max_nr_accesses = 0,
8515e01f39SSeongJae Park .min_age_region = 50,
8615e01f39SSeongJae Park .max_age_region = UINT_MAX},
8715e01f39SSeongJae Park DAMOS_PAGEOUT,
8815e01f39SSeongJae Park 0,
8915e01f39SSeongJae Park &(struct damos_quota){},
9015e01f39SSeongJae Park &(struct damos_watermarks){},
9115e01f39SSeongJae Park NUMA_NO_NODE);
9215e01f39SSeongJae Park if (!scheme) {
9315e01f39SSeongJae Park damon_destroy_ctx(ctx);
9415e01f39SSeongJae Park return -ENOMEM;
9515e01f39SSeongJae Park }
9615e01f39SSeongJae Park damon_set_schemes(ctx, &scheme, 1);
9715e01f39SSeongJae Park
982aca2546SSeongJae Park return damon_start(&ctx, 1, true);
992aca2546SSeongJae Park }
1002aca2546SSeongJae Park
damon_sample_prcl_stop(void)1012aca2546SSeongJae Park static void damon_sample_prcl_stop(void)
1022aca2546SSeongJae Park {
1032aca2546SSeongJae Park pr_info("stop\n");
1042aca2546SSeongJae Park if (ctx) {
1052aca2546SSeongJae Park damon_stop(&ctx, 1);
1062aca2546SSeongJae Park damon_destroy_ctx(ctx);
1072aca2546SSeongJae Park }
1082aca2546SSeongJae Park if (target_pidp)
1092aca2546SSeongJae Park put_pid(target_pidp);
1102aca2546SSeongJae Park }
1112aca2546SSeongJae Park
damon_sample_prcl_enable_store(const char * val,const struct kernel_param * kp)1122aca2546SSeongJae Park static int damon_sample_prcl_enable_store(
1132aca2546SSeongJae Park const char *val, const struct kernel_param *kp)
1142aca2546SSeongJae Park {
1152aca2546SSeongJae Park bool enabled = enable;
1162aca2546SSeongJae Park int err;
1172aca2546SSeongJae Park
1182aca2546SSeongJae Park err = kstrtobool(val, &enable);
1192aca2546SSeongJae Park if (err)
1202aca2546SSeongJae Park return err;
1212aca2546SSeongJae Park
1222aca2546SSeongJae Park if (enable == enabled)
1232aca2546SSeongJae Park return 0;
1242aca2546SSeongJae Park
1252aca2546SSeongJae Park if (enable)
1262aca2546SSeongJae Park return damon_sample_prcl_start();
1272aca2546SSeongJae Park damon_sample_prcl_stop();
1282aca2546SSeongJae Park return 0;
1292aca2546SSeongJae Park }
1302aca2546SSeongJae Park
damon_sample_prcl_init(void)1312aca2546SSeongJae Park static int __init damon_sample_prcl_init(void)
1322aca2546SSeongJae Park {
1332aca2546SSeongJae Park return 0;
1342aca2546SSeongJae Park }
1352aca2546SSeongJae Park
1362aca2546SSeongJae Park module_init(damon_sample_prcl_init);
137