reclaim.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * DAMON-based page reclamation
  4. *
  5. * Author: SeongJae Park <sj@kernel.org>
  6. */
  7. #define pr_fmt(fmt) "damon-reclaim: " fmt
  8. #include <linux/damon.h>
  9. #include <linux/kstrtox.h>
  10. #include <linux/module.h>
  11. #include "modules-common.h"
  12. #ifdef MODULE_PARAM_PREFIX
  13. #undef MODULE_PARAM_PREFIX
  14. #endif
  15. #define MODULE_PARAM_PREFIX "damon_reclaim."
  16. /*
  17. * Enable or disable DAMON_RECLAIM.
  18. *
  19. * You can enable DAMON_RCLAIM by setting the value of this parameter as ``Y``.
  20. * Setting it as ``N`` disables DAMON_RECLAIM. Note that DAMON_RECLAIM could
  21. * do no real monitoring and reclamation due to the watermarks-based activation
  22. * condition. Refer to below descriptions for the watermarks parameter for
  23. * this.
  24. */
  25. static bool enabled __read_mostly;
  26. /*
  27. * Make DAMON_RECLAIM reads the input parameters again, except ``enabled``.
  28. *
  29. * Input parameters that updated while DAMON_RECLAIM is running are not applied
  30. * by default. Once this parameter is set as ``Y``, DAMON_RECLAIM reads values
  31. * of parameters except ``enabled`` again. Once the re-reading is done, this
  32. * parameter is set as ``N``. If invalid parameters are found while the
  33. * re-reading, DAMON_RECLAIM will be disabled.
  34. */
  35. static bool commit_inputs __read_mostly;
  36. module_param(commit_inputs, bool, 0600);
  37. /*
  38. * Time threshold for cold memory regions identification in microseconds.
  39. *
  40. * If a memory region is not accessed for this or longer time, DAMON_RECLAIM
  41. * identifies the region as cold, and reclaims. 120 seconds by default.
  42. */
  43. static unsigned long min_age __read_mostly = 120000000;
  44. module_param(min_age, ulong, 0600);
  45. static struct damos_quota damon_reclaim_quota = {
  46. /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */
  47. .ms = 10,
  48. .sz = 128 * 1024 * 1024,
  49. .reset_interval = 1000,
  50. /* Within the quota, page out older regions first. */
  51. .weight_sz = 0,
  52. .weight_nr_accesses = 0,
  53. .weight_age = 1
  54. };
  55. DEFINE_DAMON_MODULES_DAMOS_QUOTAS(damon_reclaim_quota);
  56. /*
  57. * Desired level of memory pressure-stall time in microseconds.
  58. *
  59. * While keeping the caps that set by other quotas, DAMON_RECLAIM automatically
  60. * increases and decreases the effective level of the quota aiming this level of
  61. * memory pressure is incurred. System-wide ``some`` memory PSI in microseconds
  62. * per quota reset interval (``quota_reset_interval_ms``) is collected and
  63. * compared to this value to see if the aim is satisfied. Value zero means
  64. * disabling this auto-tuning feature.
  65. *
  66. * Disabled by default.
  67. */
  68. static unsigned long quota_mem_pressure_us __read_mostly;
  69. module_param(quota_mem_pressure_us, ulong, 0600);
  70. /*
  71. * User-specifiable feedback for auto-tuning of the effective quota.
  72. *
  73. * While keeping the caps that set by other quotas, DAMON_RECLAIM automatically
  74. * increases and decreases the effective level of the quota aiming receiving this
  75. * feedback of value ``10,000`` from the user. DAMON_RECLAIM assumes the feedback
  76. * value and the quota are positively proportional. Value zero means disabling
  77. * this auto-tuning feature.
  78. *
  79. * Disabled by default.
  80. *
  81. */
  82. static unsigned long quota_autotune_feedback __read_mostly;
  83. module_param(quota_autotune_feedback, ulong, 0600);
  84. static struct damos_watermarks damon_reclaim_wmarks = {
  85. .metric = DAMOS_WMARK_FREE_MEM_RATE,
  86. .interval = 5000000, /* 5 seconds */
  87. .high = 500, /* 50 percent */
  88. .mid = 400, /* 40 percent */
  89. .low = 200, /* 20 percent */
  90. };
  91. DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_reclaim_wmarks);
  92. static struct damon_attrs damon_reclaim_mon_attrs = {
  93. .sample_interval = 5000, /* 5 ms */
  94. .aggr_interval = 100000, /* 100 ms */
  95. .ops_update_interval = 0,
  96. .min_nr_regions = 10,
  97. .max_nr_regions = 1000,
  98. };
  99. DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_reclaim_mon_attrs);
  100. /*
  101. * Start of the target memory region in physical address.
  102. *
  103. * The start physical address of memory region that DAMON_RECLAIM will do work
  104. * against. By default, biggest System RAM is used as the region.
  105. */
  106. static unsigned long monitor_region_start __read_mostly;
  107. module_param(monitor_region_start, ulong, 0600);
  108. /*
  109. * End of the target memory region in physical address.
  110. *
  111. * The end physical address of memory region that DAMON_RECLAIM will do work
  112. * against. By default, biggest System RAM is used as the region.
  113. */
  114. static unsigned long monitor_region_end __read_mostly;
  115. module_param(monitor_region_end, ulong, 0600);
  116. /*
  117. * Scale factor for DAMON_RECLAIM to ops address conversion.
  118. *
  119. * This parameter must not be set to 0.
  120. */
  121. static unsigned long addr_unit __read_mostly = 1;
  122. /*
  123. * Skip anonymous pages reclamation.
  124. *
  125. * If this parameter is set as ``Y``, DAMON_RECLAIM does not reclaim anonymous
  126. * pages. By default, ``N``.
  127. */
  128. static bool skip_anon __read_mostly;
  129. module_param(skip_anon, bool, 0600);
  130. /*
  131. * PID of the DAMON thread
  132. *
  133. * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
  134. * Else, -1.
  135. */
  136. static int kdamond_pid __read_mostly = -1;
  137. module_param(kdamond_pid, int, 0400);
  138. static struct damos_stat damon_reclaim_stat;
  139. DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
  140. reclaim_tried_regions, reclaimed_regions, quota_exceeds);
  141. static struct damon_ctx *ctx;
  142. static struct damon_target *target;
  143. static struct damos *damon_reclaim_new_scheme(void)
  144. {
  145. struct damos_access_pattern pattern = {
  146. /* Find regions having PAGE_SIZE or larger size */
  147. .min_sz_region = PAGE_SIZE,
  148. .max_sz_region = ULONG_MAX,
  149. /* and not accessed at all */
  150. .min_nr_accesses = 0,
  151. .max_nr_accesses = 0,
  152. /* for min_age or more micro-seconds */
  153. .min_age_region = min_age /
  154. damon_reclaim_mon_attrs.aggr_interval,
  155. .max_age_region = UINT_MAX,
  156. };
  157. return damon_new_scheme(
  158. &pattern,
  159. /* page out those, as soon as found */
  160. DAMOS_PAGEOUT,
  161. /* for each aggregation interval */
  162. 0,
  163. /* under the quota. */
  164. &damon_reclaim_quota,
  165. /* (De)activate this according to the watermarks. */
  166. &damon_reclaim_wmarks,
  167. NUMA_NO_NODE);
  168. }
  169. static int damon_reclaim_apply_parameters(void)
  170. {
  171. struct damon_ctx *param_ctx;
  172. struct damon_target *param_target;
  173. struct damos *scheme;
  174. struct damos_quota_goal *goal;
  175. struct damos_filter *filter;
  176. int err;
  177. err = damon_modules_new_paddr_ctx_target(&param_ctx, &param_target);
  178. if (err)
  179. return err;
  180. /*
  181. * If monitor_region_start/end are unset, always silently
  182. * reset addr_unit to 1.
  183. */
  184. if (!monitor_region_start && !monitor_region_end)
  185. addr_unit = 1;
  186. param_ctx->addr_unit = addr_unit;
  187. param_ctx->min_region_sz = max(DAMON_MIN_REGION_SZ / addr_unit, 1);
  188. if (!damon_reclaim_mon_attrs.aggr_interval) {
  189. err = -EINVAL;
  190. goto out;
  191. }
  192. err = damon_set_attrs(param_ctx, &damon_reclaim_mon_attrs);
  193. if (err)
  194. goto out;
  195. err = -ENOMEM;
  196. scheme = damon_reclaim_new_scheme();
  197. if (!scheme)
  198. goto out;
  199. damon_set_schemes(param_ctx, &scheme, 1);
  200. if (quota_mem_pressure_us) {
  201. goal = damos_new_quota_goal(DAMOS_QUOTA_SOME_MEM_PSI_US,
  202. quota_mem_pressure_us);
  203. if (!goal)
  204. goto out;
  205. damos_add_quota_goal(&scheme->quota, goal);
  206. }
  207. if (quota_autotune_feedback) {
  208. goal = damos_new_quota_goal(DAMOS_QUOTA_USER_INPUT, 10000);
  209. if (!goal)
  210. goto out;
  211. goal->current_value = quota_autotune_feedback;
  212. damos_add_quota_goal(&scheme->quota, goal);
  213. }
  214. if (skip_anon) {
  215. filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false);
  216. if (!filter)
  217. goto out;
  218. damos_add_filter(scheme, filter);
  219. }
  220. err = damon_set_region_biggest_system_ram_default(param_target,
  221. &monitor_region_start,
  222. &monitor_region_end,
  223. param_ctx->min_region_sz);
  224. if (err)
  225. goto out;
  226. err = damon_commit_ctx(ctx, param_ctx);
  227. out:
  228. damon_destroy_ctx(param_ctx);
  229. return err;
  230. }
  231. static int damon_reclaim_handle_commit_inputs(void)
  232. {
  233. int err;
  234. if (!commit_inputs)
  235. return 0;
  236. err = damon_reclaim_apply_parameters();
  237. commit_inputs = false;
  238. return err;
  239. }
  240. static int damon_reclaim_damon_call_fn(void *arg)
  241. {
  242. struct damon_ctx *c = arg;
  243. struct damos *s;
  244. /* update the stats parameter */
  245. damon_for_each_scheme(s, c)
  246. damon_reclaim_stat = s->stat;
  247. return damon_reclaim_handle_commit_inputs();
  248. }
  249. static struct damon_call_control call_control = {
  250. .fn = damon_reclaim_damon_call_fn,
  251. .repeat = true,
  252. };
  253. static int damon_reclaim_turn(bool on)
  254. {
  255. int err;
  256. if (!on) {
  257. err = damon_stop(&ctx, 1);
  258. if (!err)
  259. kdamond_pid = -1;
  260. return err;
  261. }
  262. err = damon_reclaim_apply_parameters();
  263. if (err)
  264. return err;
  265. err = damon_start(&ctx, 1, true);
  266. if (err)
  267. return err;
  268. kdamond_pid = damon_kdamond_pid(ctx);
  269. if (kdamond_pid < 0)
  270. return kdamond_pid;
  271. return damon_call(ctx, &call_control);
  272. }
  273. static int damon_reclaim_addr_unit_store(const char *val,
  274. const struct kernel_param *kp)
  275. {
  276. unsigned long input_addr_unit;
  277. int err = kstrtoul(val, 0, &input_addr_unit);
  278. if (err)
  279. return err;
  280. if (!input_addr_unit)
  281. return -EINVAL;
  282. addr_unit = input_addr_unit;
  283. return 0;
  284. }
  285. static const struct kernel_param_ops addr_unit_param_ops = {
  286. .set = damon_reclaim_addr_unit_store,
  287. .get = param_get_ulong,
  288. };
  289. module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
  290. MODULE_PARM_DESC(addr_unit,
  291. "Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)");
  292. static int damon_reclaim_enabled_store(const char *val,
  293. const struct kernel_param *kp)
  294. {
  295. bool is_enabled = enabled;
  296. bool enable;
  297. int err;
  298. err = kstrtobool(val, &enable);
  299. if (err)
  300. return err;
  301. if (is_enabled == enable)
  302. return 0;
  303. /* Called before init function. The function will handle this. */
  304. if (!damon_initialized())
  305. goto set_param_out;
  306. err = damon_reclaim_turn(enable);
  307. if (err)
  308. return err;
  309. set_param_out:
  310. enabled = enable;
  311. return err;
  312. }
  313. static const struct kernel_param_ops enabled_param_ops = {
  314. .set = damon_reclaim_enabled_store,
  315. .get = param_get_bool,
  316. };
  317. module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
  318. MODULE_PARM_DESC(enabled,
  319. "Enable or disable DAMON_RECLAIM (default: disabled)");
  320. static int __init damon_reclaim_init(void)
  321. {
  322. int err;
  323. if (!damon_initialized()) {
  324. err = -ENOMEM;
  325. goto out;
  326. }
  327. err = damon_modules_new_paddr_ctx_target(&ctx, &target);
  328. if (err)
  329. goto out;
  330. call_control.data = ctx;
  331. /* 'enabled' has set before this function, probably via command line */
  332. if (enabled)
  333. err = damon_reclaim_turn(true);
  334. out:
  335. if (err && enabled)
  336. enabled = false;
  337. return err;
  338. }
  339. module_init(damon_reclaim_init);