Docs/ABI/damon: document 'schemes/<s>/tried_regions' sysfs directory
[linux-block.git] / mm / damon / reclaim.c
CommitLineData
43b0536c
SP
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DAMON-based page reclamation
4 *
5 * Author: SeongJae Park <sj@kernel.org>
6 */
7
8#define pr_fmt(fmt) "damon-reclaim: " fmt
9
10#include <linux/damon.h>
43b0536c 11#include <linux/module.h>
43b0536c 12
fdfc119c
SP
13#include "modules-common.h"
14
43b0536c
SP
15#ifdef MODULE_PARAM_PREFIX
16#undef MODULE_PARAM_PREFIX
17#endif
18#define MODULE_PARAM_PREFIX "damon_reclaim."
19
20/*
21 * Enable or disable DAMON_RECLAIM.
22 *
23 * You can enable DAMON_RCLAIM by setting the value of this parameter as ``Y``.
24 * Setting it as ``N`` disables DAMON_RECLAIM. Note that DAMON_RECLAIM could
25 * do no real monitoring and reclamation due to the watermarks-based activation
26 * condition. Refer to below descriptions for the watermarks parameter for
27 * this.
28 */
29static bool enabled __read_mostly;
43b0536c 30
e035c280
SP
31/*
32 * Make DAMON_RECLAIM reads the input parameters again, except ``enabled``.
33 *
34 * Input parameters that updated while DAMON_RECLAIM is running are not applied
35 * by default. Once this parameter is set as ``Y``, DAMON_RECLAIM reads values
36 * of parametrs except ``enabled`` again. Once the re-reading is done, this
37 * parameter is set as ``N``. If invalid parameters are found while the
38 * re-reading, DAMON_RECLAIM will be disabled.
39 */
40static bool commit_inputs __read_mostly;
41module_param(commit_inputs, bool, 0600);
42
43b0536c
SP
43/*
44 * Time threshold for cold memory regions identification in microseconds.
45 *
46 * If a memory region is not accessed for this or longer time, DAMON_RECLAIM
47 * identifies the region as cold, and reclaims. 120 seconds by default.
48 */
49static unsigned long min_age __read_mostly = 120000000;
50module_param(min_age, ulong, 0600);
51
a9d57c73
SP
52static struct damos_quota damon_reclaim_quota = {
53 /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */
54 .ms = 10,
55 .sz = 128 * 1024 * 1024,
56 .reset_interval = 1000,
57 /* Within the quota, page out older regions first. */
58 .weight_sz = 0,
59 .weight_nr_accesses = 0,
60 .weight_age = 1
61};
62DEFINE_DAMON_MODULES_DAMOS_QUOTAS(damon_reclaim_quota);
43b0536c 63
81f8f57f 64static struct damos_watermarks damon_reclaim_wmarks = {
34f47ea6
SP
65 .metric = DAMOS_WMARK_FREE_MEM_RATE,
66 .interval = 5000000, /* 5 seconds */
67 .high = 500, /* 50 percent */
68 .mid = 400, /* 40 percent */
69 .low = 200, /* 20 percent */
70};
71DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_reclaim_wmarks);
43b0536c 72
8c341ae3 73static struct damon_attrs damon_reclaim_mon_attrs = {
fdfc119c
SP
74 .sample_interval = 5000, /* 5 ms */
75 .aggr_interval = 100000, /* 100 ms */
8c341ae3
SP
76 .ops_update_interval = 0,
77 .min_nr_regions = 10,
78 .max_nr_regions = 1000,
79};
fdfc119c 80DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_reclaim_mon_attrs);
43b0536c
SP
81
82/*
83 * Start of the target memory region in physical address.
84 *
85 * The start physical address of memory region that DAMON_RECLAIM will do work
86 * against. By default, biggest System RAM is used as the region.
87 */
88static unsigned long monitor_region_start __read_mostly;
89module_param(monitor_region_start, ulong, 0600);
90
91/*
92 * End of the target memory region in physical address.
93 *
94 * The end physical address of memory region that DAMON_RECLAIM will do work
95 * against. By default, biggest System RAM is used as the region.
96 */
97static unsigned long monitor_region_end __read_mostly;
98module_param(monitor_region_end, ulong, 0600);
99
100/*
101 * PID of the DAMON thread
102 *
103 * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
104 * Else, -1.
105 */
106static int kdamond_pid __read_mostly = -1;
107module_param(kdamond_pid, int, 0400);
108
b71f3ea8
SP
109static struct damos_stat damon_reclaim_stat;
110DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
111 reclaim_tried_regions, reclaimed_regions, quota_exceeds);
60e52e7c 112
43b0536c
SP
113static struct damon_ctx *ctx;
114static struct damon_target *target;
115
43b0536c
SP
116static struct damos *damon_reclaim_new_scheme(void)
117{
f5a79d7c
YD
118 struct damos_access_pattern pattern = {
119 /* Find regions having PAGE_SIZE or larger size */
120 .min_sz_region = PAGE_SIZE,
121 .max_sz_region = ULONG_MAX,
122 /* and not accessed at all */
123 .min_nr_accesses = 0,
124 .max_nr_accesses = 0,
125 /* for min_age or more micro-seconds */
8c341ae3
SP
126 .min_age_region = min_age /
127 damon_reclaim_mon_attrs.aggr_interval,
f5a79d7c
YD
128 .max_age_region = UINT_MAX,
129 };
f5a79d7c
YD
130
131 return damon_new_scheme(
132 &pattern,
43b0536c
SP
133 /* page out those, as soon as found */
134 DAMOS_PAGEOUT,
135 /* under the quota. */
a9d57c73 136 &damon_reclaim_quota,
43b0536c 137 /* (De)activate this according to the watermarks. */
34f47ea6 138 &damon_reclaim_wmarks);
43b0536c
SP
139}
140
e035c280 141static int damon_reclaim_apply_parameters(void)
43b0536c 142{
43b0536c 143 struct damos *scheme;
e035c280 144 int err = 0;
43b0536c 145
8c341ae3 146 err = damon_set_attrs(ctx, &damon_reclaim_mon_attrs);
43b0536c
SP
147 if (err)
148 return err;
149
e035c280
SP
150 /* Will be freed by next 'damon_set_schemes()' below */
151 scheme = damon_reclaim_new_scheme();
152 if (!scheme)
153 return -ENOMEM;
cc713520 154 damon_set_schemes(ctx, &scheme, 1);
e035c280 155
233f0b31
KX
156 return damon_set_region_biggest_system_ram_default(target,
157 &monitor_region_start,
158 &monitor_region_end);
e035c280 159}
43b0536c 160
e035c280
SP
161static int damon_reclaim_turn(bool on)
162{
163 int err;
164
165 if (!on) {
166 err = damon_stop(&ctx, 1);
167 if (!err)
168 kdamond_pid = -1;
169 return err;
43b0536c 170 }
e035c280
SP
171
172 err = damon_reclaim_apply_parameters();
43b0536c 173 if (err)
e035c280 174 return err;
43b0536c 175
8b9b0d33 176 err = damon_start(&ctx, 1, true);
e035c280
SP
177 if (err)
178 return err;
179 kdamond_pid = ctx->kdamond->pid;
180 return 0;
43b0536c
SP
181}
182
d79905c7 183static int damon_reclaim_enabled_store(const char *val,
059342d1
HT
184 const struct kernel_param *kp)
185{
04e98764
SP
186 bool is_enabled = enabled;
187 bool enable;
188 int err;
059342d1 189
04e98764
SP
190 err = strtobool(val, &enable);
191 if (err)
192 return err;
059342d1 193
04e98764
SP
194 if (is_enabled == enable)
195 return 0;
29492829 196
04e98764
SP
197 /* Called before init function. The function will handle this. */
198 if (!ctx)
199 goto set_param_out;
200
201 err = damon_reclaim_turn(enable);
202 if (err)
203 return err;
204
205set_param_out:
206 enabled = enable;
207 return err;
059342d1
HT
208}
209
210static const struct kernel_param_ops enabled_param_ops = {
d79905c7 211 .set = damon_reclaim_enabled_store,
059342d1
HT
212 .get = param_get_bool,
213};
214
215module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
216MODULE_PARM_DESC(enabled,
217 "Enable or disable DAMON_RECLAIM (default: disabled)");
218
f25ab3bd
SP
219static int damon_reclaim_handle_commit_inputs(void)
220{
221 int err;
222
223 if (!commit_inputs)
224 return 0;
225
226 err = damon_reclaim_apply_parameters();
227 commit_inputs = false;
228 return err;
229}
230
60e52e7c
SP
231static int damon_reclaim_after_aggregation(struct damon_ctx *c)
232{
233 struct damos *s;
234
235 /* update the stats parameter */
b71f3ea8
SP
236 damon_for_each_scheme(s, c)
237 damon_reclaim_stat = s->stat;
e035c280 238
f25ab3bd 239 return damon_reclaim_handle_commit_inputs();
e035c280
SP
240}
241
242static int damon_reclaim_after_wmarks_check(struct damon_ctx *c)
243{
f25ab3bd 244 return damon_reclaim_handle_commit_inputs();
60e52e7c
SP
245}
246
43b0536c
SP
247static int __init damon_reclaim_init(void)
248{
7ae2c17f 249 int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
43b0536c 250
7ae2c17f
SP
251 if (err)
252 return err;
4d69c345 253
e035c280 254 ctx->callback.after_wmarks_check = damon_reclaim_after_wmarks_check;
60e52e7c 255 ctx->callback.after_aggregation = damon_reclaim_after_aggregation;
43b0536c 256
04e98764
SP
257 /* 'enabled' has set before this function, probably via command line */
258 if (enabled)
259 err = damon_reclaim_turn(true);
29492829 260
04e98764 261 return err;
43b0536c
SP
262}
263
264module_init(damon_reclaim_init);