reclaim.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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 parametrs 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. * Skip anonymous pages reclamation.
  118. *
  119. * If this parameter is set as ``Y``, DAMON_RECLAIM does not reclaim anonymous
  120. * pages. By default, ``N``.
  121. */
  122. static bool skip_anon __read_mostly;
  123. module_param(skip_anon, bool, 0600);
  124. /*
  125. * PID of the DAMON thread
  126. *
  127. * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
  128. * Else, -1.
  129. */
  130. static int kdamond_pid __read_mostly = -1;
  131. module_param(kdamond_pid, int, 0400);
  132. static struct damos_stat damon_reclaim_stat;
  133. DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
  134. reclaim_tried_regions, reclaimed_regions, quota_exceeds);
  135. static struct damon_ctx *ctx;
  136. static struct damon_target *target;
  137. static struct damos *damon_reclaim_new_scheme(void)
  138. {
  139. struct damos_access_pattern pattern = {
  140. /* Find regions having PAGE_SIZE or larger size */
  141. .min_sz_region = PAGE_SIZE,
  142. .max_sz_region = ULONG_MAX,
  143. /* and not accessed at all */
  144. .min_nr_accesses = 0,
  145. .max_nr_accesses = 0,
  146. /* for min_age or more micro-seconds */
  147. .min_age_region = min_age /
  148. damon_reclaim_mon_attrs.aggr_interval,
  149. .max_age_region = UINT_MAX,
  150. };
  151. return damon_new_scheme(
  152. &pattern,
  153. /* page out those, as soon as found */
  154. DAMOS_PAGEOUT,
  155. /* for each aggregation interval */
  156. 0,
  157. /* under the quota. */
  158. &damon_reclaim_quota,
  159. /* (De)activate this according to the watermarks. */
  160. &damon_reclaim_wmarks,
  161. NUMA_NO_NODE);
  162. }
  163. static int damon_reclaim_apply_parameters(void)
  164. {
  165. struct damon_ctx *param_ctx;
  166. struct damon_target *param_target;
  167. struct damos *scheme;
  168. struct damos_quota_goal *goal;
  169. struct damos_filter *filter;
  170. int err;
  171. err = damon_modules_new_paddr_ctx_target(&param_ctx, &param_target);
  172. if (err)
  173. return err;
  174. err = damon_set_attrs(ctx, &damon_reclaim_mon_attrs);
  175. if (err)
  176. goto out;
  177. err = -ENOMEM;
  178. scheme = damon_reclaim_new_scheme();
  179. if (!scheme)
  180. goto out;
  181. damon_set_schemes(ctx, &scheme, 1);
  182. if (quota_mem_pressure_us) {
  183. goal = damos_new_quota_goal(DAMOS_QUOTA_SOME_MEM_PSI_US,
  184. quota_mem_pressure_us);
  185. if (!goal)
  186. goto out;
  187. damos_add_quota_goal(&scheme->quota, goal);
  188. }
  189. if (quota_autotune_feedback) {
  190. goal = damos_new_quota_goal(DAMOS_QUOTA_USER_INPUT, 10000);
  191. if (!goal)
  192. goto out;
  193. goal->current_value = quota_autotune_feedback;
  194. damos_add_quota_goal(&scheme->quota, goal);
  195. }
  196. if (skip_anon) {
  197. filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true);
  198. if (!filter)
  199. goto out;
  200. damos_add_filter(scheme, filter);
  201. }
  202. err = damon_set_region_biggest_system_ram_default(param_target,
  203. &monitor_region_start,
  204. &monitor_region_end);
  205. if (err)
  206. goto out;
  207. err = damon_commit_ctx(ctx, param_ctx);
  208. out:
  209. damon_destroy_ctx(param_ctx);
  210. return err;
  211. }
  212. static int damon_reclaim_turn(bool on)
  213. {
  214. int err;
  215. if (!on) {
  216. err = damon_stop(&ctx, 1);
  217. if (!err)
  218. kdamond_pid = -1;
  219. return err;
  220. }
  221. err = damon_reclaim_apply_parameters();
  222. if (err)
  223. return err;
  224. err = damon_start(&ctx, 1, true);
  225. if (err)
  226. return err;
  227. kdamond_pid = ctx->kdamond->pid;
  228. return 0;
  229. }
  230. static int damon_reclaim_enabled_store(const char *val,
  231. const struct kernel_param *kp)
  232. {
  233. bool is_enabled = enabled;
  234. bool enable;
  235. int err;
  236. err = kstrtobool(val, &enable);
  237. if (err)
  238. return err;
  239. if (is_enabled == enable)
  240. return 0;
  241. /* Called before init function. The function will handle this. */
  242. if (!ctx)
  243. goto set_param_out;
  244. err = damon_reclaim_turn(enable);
  245. if (err)
  246. return err;
  247. set_param_out:
  248. enabled = enable;
  249. return err;
  250. }
  251. static const struct kernel_param_ops enabled_param_ops = {
  252. .set = damon_reclaim_enabled_store,
  253. .get = param_get_bool,
  254. };
  255. module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
  256. MODULE_PARM_DESC(enabled,
  257. "Enable or disable DAMON_RECLAIM (default: disabled)");
  258. static int damon_reclaim_handle_commit_inputs(void)
  259. {
  260. int err;
  261. if (!commit_inputs)
  262. return 0;
  263. err = damon_reclaim_apply_parameters();
  264. commit_inputs = false;
  265. return err;
  266. }
  267. static int damon_reclaim_after_aggregation(struct damon_ctx *c)
  268. {
  269. struct damos *s;
  270. /* update the stats parameter */
  271. damon_for_each_scheme(s, c)
  272. damon_reclaim_stat = s->stat;
  273. return damon_reclaim_handle_commit_inputs();
  274. }
  275. static int damon_reclaim_after_wmarks_check(struct damon_ctx *c)
  276. {
  277. return damon_reclaim_handle_commit_inputs();
  278. }
  279. static int __init damon_reclaim_init(void)
  280. {
  281. int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
  282. if (err)
  283. return err;
  284. ctx->callback.after_wmarks_check = damon_reclaim_after_wmarks_check;
  285. ctx->callback.after_aggregation = damon_reclaim_after_aggregation;
  286. /* 'enabled' has set before this function, probably via command line */
  287. if (enabled)
  288. err = damon_reclaim_turn(true);
  289. return err;
  290. }
  291. module_init(damon_reclaim_init);