1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * working set size estimation: monitor access pattern of given process and
4  * print estimated working set size (total size of regions that showing some
5  * access).
6  */
7 
8 #define pr_fmt(fmt) "damon_sample_wsse: " fmt
9 
10 #include <linux/damon.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 
15 static int target_pid __read_mostly;
16 module_param(target_pid, int, 0600);
17 
18 static int damon_sample_wsse_enable_store(
19 		const char *val, const struct kernel_param *kp);
20 
21 static const struct kernel_param_ops enable_param_ops = {
22 	.set = damon_sample_wsse_enable_store,
23 	.get = param_get_bool,
24 };
25 
26 static bool enable __read_mostly;
27 module_param_cb(enable, &enable_param_ops, &enable, 0600);
28 MODULE_PARM_DESC(enable, "Enable or disable DAMON_SAMPLE_WSSE");
29 
30 static struct damon_ctx *ctx;
31 static struct pid *target_pidp;
32 
damon_sample_wsse_after_aggregate(struct damon_ctx * c)33 static int damon_sample_wsse_after_aggregate(struct damon_ctx *c)
34 {
35 	struct damon_target *t;
36 
37 	damon_for_each_target(t, c) {
38 		struct damon_region *r;
39 		unsigned long wss = 0;
40 
41 		damon_for_each_region(r, t) {
42 			if (r->nr_accesses > 0)
43 				wss += r->ar.end - r->ar.start;
44 		}
45 		pr_info("wss: %lu\n", wss);
46 	}
47 	return 0;
48 }
49 
damon_sample_wsse_start(void)50 static int damon_sample_wsse_start(void)
51 {
52 	struct damon_target *target;
53 
54 	pr_info("start\n");
55 
56 	ctx = damon_new_ctx();
57 	if (!ctx)
58 		return -ENOMEM;
59 	if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
60 		damon_destroy_ctx(ctx);
61 		return -EINVAL;
62 	}
63 
64 	target = damon_new_target();
65 	if (!target) {
66 		damon_destroy_ctx(ctx);
67 		return -ENOMEM;
68 	}
69 	damon_add_target(ctx, target);
70 	target_pidp = find_get_pid(target_pid);
71 	if (!target_pidp) {
72 		damon_destroy_ctx(ctx);
73 		return -EINVAL;
74 	}
75 	target->pid = target_pidp;
76 
77 	ctx->callback.after_aggregation = damon_sample_wsse_after_aggregate;
78 	return damon_start(&ctx, 1, true);
79 }
80 
damon_sample_wsse_stop(void)81 static void damon_sample_wsse_stop(void)
82 {
83 	pr_info("stop\n");
84 	if (ctx) {
85 		damon_stop(&ctx, 1);
86 		damon_destroy_ctx(ctx);
87 	}
88 	if (target_pidp)
89 		put_pid(target_pidp);
90 }
91 
damon_sample_wsse_enable_store(const char * val,const struct kernel_param * kp)92 static int damon_sample_wsse_enable_store(
93 		const char *val, const struct kernel_param *kp)
94 {
95 	bool enabled = enable;
96 	int err;
97 
98 	err = kstrtobool(val, &enable);
99 	if (err)
100 		return err;
101 
102 	if (enable == enabled)
103 		return 0;
104 
105 	if (enable)
106 		return damon_sample_wsse_start();
107 	damon_sample_wsse_stop();
108 	return 0;
109 }
110 
damon_sample_wsse_init(void)111 static int __init damon_sample_wsse_init(void)
112 {
113 	return 0;
114 }
115 
116 module_init(damon_sample_wsse_init);
117