xref: /linux/samples/damon/wsse.c (revision c1db0cb157c6ddd6e24eb62673022b665ca688b9)
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 #ifdef MODULE_PARAM_PREFIX
16 #undef MODULE_PARAM_PREFIX
17 #endif
18 #define MODULE_PARAM_PREFIX "damon_sample_wsse."
19 
20 static int target_pid __read_mostly;
21 module_param(target_pid, int, 0600);
22 
23 static int damon_sample_wsse_enable_store(
24 		const char *val, const struct kernel_param *kp);
25 
26 static const struct kernel_param_ops enable_param_ops = {
27 	.set = damon_sample_wsse_enable_store,
28 	.get = param_get_bool,
29 };
30 
31 static bool enable __read_mostly;
32 module_param_cb(enable, &enable_param_ops, &enable, 0600);
33 MODULE_PARM_DESC(enable, "Enable or disable DAMON_SAMPLE_WSSE");
34 
35 static struct damon_ctx *ctx;
36 static struct pid *target_pidp;
37 
38 static int damon_sample_wsse_after_aggregate(struct damon_ctx *c)
39 {
40 	struct damon_target *t;
41 
42 	damon_for_each_target(t, c) {
43 		struct damon_region *r;
44 		unsigned long wss = 0;
45 
46 		damon_for_each_region(r, t) {
47 			if (r->nr_accesses > 0)
48 				wss += r->ar.end - r->ar.start;
49 		}
50 		pr_info("wss: %lu\n", wss);
51 	}
52 	return 0;
53 }
54 
55 static int damon_sample_wsse_start(void)
56 {
57 	struct damon_target *target;
58 
59 	pr_info("start\n");
60 
61 	ctx = damon_new_ctx();
62 	if (!ctx)
63 		return -ENOMEM;
64 	if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
65 		damon_destroy_ctx(ctx);
66 		return -EINVAL;
67 	}
68 
69 	target = damon_new_target();
70 	if (!target) {
71 		damon_destroy_ctx(ctx);
72 		return -ENOMEM;
73 	}
74 	damon_add_target(ctx, target);
75 	target_pidp = find_get_pid(target_pid);
76 	if (!target_pidp) {
77 		damon_destroy_ctx(ctx);
78 		return -EINVAL;
79 	}
80 	target->pid = target_pidp;
81 
82 	ctx->callback.after_aggregation = damon_sample_wsse_after_aggregate;
83 	return damon_start(&ctx, 1, true);
84 }
85 
86 static void damon_sample_wsse_stop(void)
87 {
88 	pr_info("stop\n");
89 	if (ctx) {
90 		damon_stop(&ctx, 1);
91 		damon_destroy_ctx(ctx);
92 	}
93 	if (target_pidp)
94 		put_pid(target_pidp);
95 }
96 
97 static bool init_called;
98 
99 static int damon_sample_wsse_enable_store(
100 		const char *val, const struct kernel_param *kp)
101 {
102 	bool enabled = enable;
103 	int err;
104 
105 	err = kstrtobool(val, &enable);
106 	if (err)
107 		return err;
108 
109 	if (enable == enabled)
110 		return 0;
111 
112 	if (enable) {
113 		err = damon_sample_wsse_start();
114 		if (err)
115 			enable = false;
116 		return err;
117 	}
118 	damon_sample_wsse_stop();
119 	return 0;
120 }
121 
122 static int __init damon_sample_wsse_init(void)
123 {
124 	int err = 0;
125 
126 	init_called = true;
127 	if (enable) {
128 		err = damon_sample_wsse_start();
129 		if (err)
130 			enable = false;
131 	}
132 	return err;
133 }
134 
135 module_init(damon_sample_wsse_init);
136