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