mm/damon: let users feed and tame/auto-tune DAMOS
Subsystems (5)
SeongJae Park
maintainercover mm/damon: let users feed and tame/auto-tune DAMOS
Introduce Aim-oriented Feedback-driven DAMOS Aggressiveness Auto-tuning. It makes DAMOS self-tuned with periodic simple user feedback.
Patchset Changelog
==================
From RFC
(https://lore.kernel.org/damon/[email protected]/)
- Wordsmith commit messages and cover letter
Background: DAMOS Control Difficulty
====================================
DAMOS helps users easily implement access pattern aware system operations. However, controlling DAMOS in the wild is not that easy.
The basic way for DAMOS control is specifying the target access pattern. In this approach, the user is assumed to well understand the access pattern and the characteristics of the system and the workloads. Though there are useful tools for that, it takes time and effort depending on the complexity and the dynamicity of the system and the workloads. After all, the access pattern consists of three ranges, namely the size, the access rate, and the age of the regions. It means users need to tune six parameters, which is anyway not a simple task.
One of the worst cases would be DAMOS being too aggressive like a berserker, and therefore consuming too much system resource and making unwanted radical system operations. To let users avoid such cases, DAMOS allows users to set the upper-limit of the schemes' aggressiveness, namely DAMOS quota. DAMOS further provides its best-effort under the limit by prioritizing regions based on the access pattern of the regions. For example, users can ask DAMOS to page out up to 100 MiB of memory regions per second. Then DAMOS pages out regions that are not accessed for a longer time (colder) first under the limit. This allows users to set the target access pattern a bit naive with wider ranges, and focus on tuning only one parameter, the quota. In other words, the number of parameters to tune can be reduced from six to one.
Still, however, the optimum value for the quota depends on the system and the workloads' characteristics, so not that simple. The number of parameters to tune can also increase again if the user needs to run multiple schemes.
Aim-oriented Feedback-driven DAMOS Aggressiveness Auto Tuning
=============================================================
Users would use DAMOS since they want to achieve something with it. They will likely have measurable metrics representing the achievement and the target number of the metric like SLO, and continuously measure that anyway. While the additional cost of getting the information is nearly zero, it could be useful for DAMOS to understand how appropriate its current aggressiveness is set, and adjust it on its own to make the metric value more close to the target.
Based on this idea, we introduce a new way of tuning DAMOS with nearly zero additional effort, namely Aim-oriented Feedback-driven DAMOS Aggressiveness Auto Tuning. It asks users to provide feedback representing how well DAMOS is doing relative to the users' aim. Then DAMOS adjusts its aggressiveness, specifically the quota that provides the best effort result under the limit, based on the current level of the aggressiveness and the users' feedback.
Implementation
--------------
The implementation asks users to represent the feedback with score numbers. The scores could be anything including user-space specific metrics including latency and throughput of special user-space workloads, and system metrics including free memory ratio, memory pressure stall time (PSI), and active to inactive LRU lists size ratio. The feedback scores and the aggressiveness of the given DAMOS scheme are assumed to be positively proportional, though. Selecting metrics of the assumption is the users' responsibility.
The core logic uses the below simple feedback loop algorithm to calculate the next aggressiveness level of the scheme from the current aggressiveness level and the current feedback (target_score and current_score). It calculates the compensation for next aggressiveness as a proportion of current aggressiveness and distance to the target score. As a result, it arrives at the near-goal state in a short time using big steps when it's far from the goal, but avoids making unnecessarily radical changes that could turn out to be a bad decision using small steps when its near to the goal.
f(n) = max(1, f(n - 1) * ((target_score - current_score) / target_score + 1))
Note that the compensation value becomes negative when it's over achieving the goal. That's why the feedback metric and the aggressiveness of the scheme should be positively proportional. The distance-adaptive speed manipulation is simply applied.
Example Use Cases
-----------------
If users want to reduce the memory footprint of the system as much as possible as long as the time spent for handling the resulting memory pressure is within a threshold, they could use DAMOS scheme that reclaims cold memory regions aiming for a little level of memory pressure stall time.
If users want the active/inactive LRU lists well balanced to reduce the performance impact due to possible future memory pressure, they could use two schemes. The first one would be set to locate hot pages in the active LRU list, aiming for a specific active-to-inactive LRU list size ratio, say, 70%. The second one would be to locate cold pages in the inactive LRU list, aiming for a specific inactive-to-active LRU list size ratio, say, 30%. Then, DAMOS will balance the two schemes based on the goal and feedback.
This aim-oriented auto tuning could also be useful for general balancing-required access aware system operations such as system memory auto scaling[3] and tiered memory management[4]. These two example usages are not what current DAMOS implementation is already supporting, but require additional DAMOS action developments, though.
Evaluation: subtle memory pressure aiming proactive reclamation
---------------------------------------------------------------
To show if the implementation works as expected, we prepare four different system configurations on AWS i3.metal instances. The first setup (original) runs the workload without any DAMOS scheme. The second setup (not-tuned) runs the workload with a virtual address space-based proactive reclamation scheme that pages out memory regions that are not accessed for five seconds or more. The third setup (offline-tuned) runs the same proactive reclamation DAMOS scheme, but after making it tuned for each workload offline, using our previous user-space driven automatic tuning approach, namely DAMOOS[1]. The fourth and final setup (AFDAA) runs the scheme that is the same as that of 'not-tuned' setup, but aims to keep 0.5% of 'some' memory pressure stall time (PSI) for the last 10 seconds using the aiming-oriented auto tuning.
For each setup, we run realistic workloads from PARSEC3 and SPLASH-2X benchmark suites. For each run, we measure RSS and runtime of the workload, and 'some' memory pressure stall time (PSI) of the system. We repeat the runs five times and use averaged measurements.
For simple comparison of the results, we normalize the measurements to those of 'original'. In the case of the PSI, though, the measurement for 'original' was zero, so we normalize the value to that of 'not-tuned' scheme's result. The normalized results are shown below.
Not-tuned Offline-tuned AFDAA
RSS 0.622688178226118 0.787950678944904 0.740093483278979
runtime 1.11767826657912 1.0564674983585 1.0910833880499
PSI 1 0.727521443794069 0.308498846350299The 'not-tuned' scheme achieves about 38.7% memory saving but incur about 11.7% runtime slowdown. The 'offline-tuned' scheme achieves about 22.2% memory saving with about 5.5% runtime slowdown. It also achieves about 28.2% memory pressure stall time saving. AFDAA achieves about 26% memory saving with about 9.1% runtime slowdown. It also achieves about 69.1% memory pressure stall time saving. We repeat this test multiple times, and get consistent results. AFDAA is now integrated in our daily DAMON performance test setup.
Apparently the aggressiveness of 'AFDAA' setup is somewhere between those of 'not-tuned' and 'offline-tuned' setup, since its memory saving and runtime overhead are between those of the other two setups. Actually we set the memory pressure stall time goal aiming for this middle aggressiveness. The difference in the two metrics are not significant, though. However, it shows significant saving of the memory pressure stall time, which was the goal of the auto-tuning, over the two variants. Hence, we conclude the automatic tuning is working as expected.
Please note that the AFDAA setup is only for the evaluation, and therefore intentionally set a bit aggressive. It might not be appropriate for production environments.
The test code is also available[2], so you could reproduce it on your system and workloads.
Patches Sequence
================
The first four patches implement the core logic and user interfaces for the auto tuning. The first patch implements the core logic for the auto tuning, and the API for DAMOS users in the kernel space. The second patch implements basic file operations of DAMON sysfs directories and files that will be used for setting the goals and providing the feedback. The third patch connects the quota goals files inputs to the DAMOS core logic. Finally the fourth patch implements a dedicated DAMOS sysfs command for efficiently committing the quota goals feedback.
Two patches for simple tests of the logic and interfaces follow. The fifth patch implements the core logic unit test. The sixth patch implements a selftest for the DAMON Sysfs interface for the goals.
Finally, three patches for documentation follows. The seventh patch documents the design of the feature. The eighth patch updates the API doc for the new sysfs files. The final eighth patch updates the usage document for the features.
References
==========
[1] DAOS paper:
https://www.amazon.science/publications/daos-data-access-aware-operating-system
[2] Evaluation code:
https://github.com/damonitor/damon-tests/commit/3f884e61193f0166b8724554b6d06b0c449a712d [3] Memory auto scaling RFC idea: https://lore.kernel.org/damon/[email protected]/ [4] DAMON-based tiered memory management RFC idea: https://lore.kernel.org/damon/[email protected]/
SeongJae Park (9):
mm/damon/core: implement goal-oriented feedback-driven quota
auto-tuning
mm/damon/sysfs-schemes: implement files for scheme quota goals setup mm/damon/sysfs-schemes: commit damos quota goals user input to DAMOS mm/damon/sysfs-schemes: implement a command for scheme quota goals
only commit
mm/damon/core-test: add a unit test for the feedback loop algorithm selftests/damon: test quota goals directory Docs/mm/damon/design: document DAMOS quota auto tuning Docs/ABI/damon: document DAMOS quota goals Docs/admin-guide/mm/damon/usage: document for quota goals
.../ABI/testing/sysfs-kernel-mm-damon | 33 ++- Documentation/admin-guide/mm/damon/usage.rst | 48 +++- Documentation/mm/damon/design.rst | 13 + include/linux/damon.h | 19 ++ mm/damon/core-test.h | 32 +++ mm/damon/core.c | 68 ++++- mm/damon/sysfs-common.h | 3 + mm/damon/sysfs-schemes.c | 272 +++++++++++++++++- mm/damon/sysfs.c | 27 ++ tools/testing/selftests/damon/sysfs.sh | 27 ++ 10 files changed, 517 insertions(+), 25 deletions(-)
base-commit: b4e0245a831a402cae8634a4dc277a04830ff07a
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 1/9 mm/damon/core: implement goal-oriented feedback-driven quota auto-tuning
Users can effectively control the upper-limit aggressiveness of DAMOS schemes using the quota feature. The quota provides best result under the limit by prioritizing regions based on the access pattern. That said, finding the best value, which could depend on dynamic characteristics of the system and the workloads, is still challenging.
Implement a simple feedback-driven tuning mechanism and use it for automatic tuning of DAMOS quota. The implementation allows users to provide the feedback by setting a feedback score returning callback function. Then DAMOS periodically calls the function back and adjusts the quota based on the return value of the callback and current quota value.
Note that the absolute-value based time/size quotas still work as the maximum hard limits of the scheme's aggressiveness. The feedback-driven auto-tuned quota is applied only if it is not exceeding the manually set maximum limits. Same for the scheme-target access pattern and filters like other features.
--- include/linux/damon.h | 19 ++++++++++++ mm/damon/core.c | 68 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 9 deletions(-)
include/linux/damon.h +19 -0
@@ -136,6 +136,8 @@ enum damos_action {* @weight_nr_accesses: Weight of the region's nr_accesses for prioritization. * @weight_age: Weight of the region's age for prioritization. * +* @get_score: Feedback function for self-tuning quota. +* * To avoid consuming too much CPU time or IO resources for applying the * &struct damos->action to large memory, DAMON allows users to set time and/or * size quotas. The quotas can be set by writing non-zero values to &ms and
@@ -153,6 +155,17 @@ enum damos_action {* You could customize the prioritization logic by setting &weight_sz, * &weight_nr_accesses, and &weight_age, because monitoring operations are * encouraged to respect those. +* +* If @get_score function pointer is set, DAMON calls it back and get the +* return value of it for every @reset_interval. Then, DAMON adjusts the +* effective quota using the return value as a feedback score to the current +* quota, using its internal feedback loop algorithm. +* +* The feedback loop algorithem assumes the quota input and the feedback score +* output are in a positive proportional relationship, and the goal of the +* tuning is getting the feedback screo value of 10,000. If @ms and/or @sz are +* set together, those work as a hard limit quota. If neither @ms nor @sz are +* set, the mechanism starts from the quota of one byte. */ struct damos_quota {unsigned long ms;
@@ -163,6 +176,9 @@ struct damos_quota {unsigned int weight_nr_accesses;unsigned int weight_age; +unsigned long (*get_score)(void *arg); +void *get_score_arg; +/* private: */ /* For throughput estimation */ unsigned long total_charged_sz;
@@ -179,6 +195,9 @@ struct damos_quota {/* For prioritization */ unsigned long histogram[DAMOS_MAX_SCORE +1 ];unsigned int min_score; + +/* For feedback loop */ +unsigned long esz_bp; };/**
mm/damon/core.c +59 -9
92 lines not on this page · raw message
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 2/9 mm/damon/sysfs-schemes: implement files for scheme quota goals setup
In reply to SeongJae ParkImplement DAMON sysfs directories and files for the goals of DAMOS quota. Those allow users set multiple goals for their aim, with target values. Users can further enter the current score value for each goal as feedback for DAMOS.
Note that this commit is implementing only the basic file operations, and not connecting the files with the DAMOS core logic. Hence writing something to the files makes no real effect. The following commit will connect the file operations and the core logic.
--- mm/damon/sysfs-schemes.c | 224 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 3 deletions(-)
mm/damon/sysfs-schemes.c +221 -3
@@ -820,6 +820,203 @@ static const struct kobj_type damon_sysfs_watermarks_ktype = { .default_groups = damon_sysfs_watermarks_groups, }; +/* +* quota goal directory +*/ + +struct damos_sysfs_quota_goal { +struct kobject kobj; +unsigned long target_value; +unsigned long current_value; +}; + +static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc (void ) +{ +return kzalloc (sizeof (struct damos_sysfs_quota_goal ),GFP_KERNEL ); +} + +static ssize_t target_value_show (struct kobject *kobj, +struct kobj_attribute *attr,char *buf) +{ + struct damos_sysfs_quota_goal *goal = container_of(kobj, struct + damos_sysfs_quota_goal, kobj); + +return sysfs_emit (buf,"%lu\n" , goal->target_value); +} + +static ssize_t target_value_store (struct kobject *kobj, +struct kobj_attribute *attr,const char *buf,size_t count) +{ + struct damos_sysfs_quota_goal *goal = container_of(kobj, struct + damos_sysfs_quota_goal, kobj); +int err =kstrtoul (buf,0 , &goal->target_value); + +return err ? err : count; +} + +static ssize_t current_value_show (struct kobject *kobj, +struct kobj_attribute *attr,char *buf) +{ + struct damos_sysfs_quota_goal *goal = container_of(kobj, struct + damos_sysfs_quota_goal, kobj); + +return sysfs_emit (buf,"%lu\n" , goal->current_value); +} + +static ssize_t current_value_store (struct kobject *kobj, +struct kobj_attribute *attr,const char *buf,size_t count) +{ + struct damos_sysfs_quota_goal *goal = container_of(kobj, struct + damos_sysfs_quota_goal, kobj); +int err =kstrtoul (buf,0 , &goal->current_value); + +/* feed callback should check existence of this file and read value */ +return err ? err : count; +} + +static void damos_sysfs_quota_goal_release (struct kobject *kobj) +{ +/* or, notify this release to the feed callback */ +kfree (container_of(kobj ,struct damos_sysfs_quota_goal ,kobj )); +} + +static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr = +__ATTR_RW_MODE (target_value,0600 ); + +static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr = +__ATTR_RW_MODE (current_value,0600 ); + +static struct attribute *damos_sysfs_quota_goal_attrs[] = { + &damos_sysfs_quota_goal_target_value_attr.attr, + &damos_sysfs_quota_goal_current_value_attr.attr, +NULL , +}; +ATTRIBUTE_GROUPS (damos_sysfs_quota_goal); + +static const struct kobj_type damos_sysfs_quota_goal_ktype = { + .release = damos_sysfs_quota_goal_release, + .sysfs_ops = &kobj_sysfs_ops, + .default_groups = damos_sysfs_quota_goal_groups, +}; + +/* +* quota goals directory +*/ + +struct damos_sysfs_quota_goals { +struct kobject kobj; +struct damos_sysfs_quota_goal **goals_arr;/* counted by nr */ +int nr; +}; + +static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc (void ) +{ +return kzalloc (sizeof (struct damos_sysfs_quota_goals ),GFP_KERNEL ); +} + +static void damos_sysfs_quota_goals_rm_dirs ( +struct damos_sysfs_quota_goals *goals) +{ +struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr; +int i; + +for (i =0 ; i < goals->nr; i++) +kobject_put (&goals_arr[i]->kobj); + goals->nr =0 ; +kfree (goals_arr); + goals->goals_arr =NULL ; +} + +static int damos_sysfs_quota_goals_add_dirs ( +struct damos_sysfs_quota_goals *goals,int nr_goals) +{ +struct damos_sysfs_quota_goal **goals_arr, *goal; +int err, i; + +damos_sysfs_quota_goals_rm_dirs (goals); +if (!nr_goals) +return 0 ; + + goals_arr =kmalloc_array (nr_goals,sizeof (*goals_arr), +GFP_KERNEL | __GFP_NOWARN); +if (!goals_arr) +return -ENOMEM ; + goals->goals_arr = goals_arr; + +for (i =0 ; i < nr_goals; i++) { + goal =damos_sysfs_quota_goal_alloc (); +if (!goal) { +damos_sysfs_quota_goals_rm_dirs (goals); +return -ENOMEM ; + } + + err =kobject_init_and_add (&goal->kobj, + &damos_sysfs_quota_goal_ktype, &goals->kobj, +"%d" , i); +if (err) { +kobject_put (&goal->kobj); +damos_sysfs_quota_goals_rm_dirs (goals); +return err; + } + + goals_arr[i] = goal; + goals->nr++; + } +return 0 ; +} + +static ssize_t nr_goals_show (struct kobject *kobj, +struct kobj_attribute *attr,char *buf) +{ +struct damos_sysfs_quota_goals *goals =container_of (kobj, + struct damos_sysfs_quota_goals, kobj); + +return sysfs_emit (buf,"%d\n" , goals->nr); +} + +static ssize_t nr_goals_store (struct kobject *kobj, +struct kobj_attribute *attr,const char *buf,size_t count) +{ +struct damos_sysfs_quota_goals *goals; +int nr, err =kstrtoint (buf,0 , &nr); + +if (err) +return err; +if (nr <0 ) +return -EINVAL ; + + goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj); + +if (!mutex_trylock (&damon_sysfs_lock)) +return -EBUSY ; + err =damos_sysfs_quota_goals_add_dirs (goals, nr); +mutex_unlock (&damon_sysfs_lock); +if (err) +return err; + +return count; +} + +static void damos_sysfs_quota_goals_release (struct kobject *kobj) +{ +kfree (container_of(kobj ,struct damos_sysfs_quota_goals ,kobj )); +} + +static struct kobj_attribute damos_sysfs_quota_goals_nr_attr = +__ATTR_RW_MODE (nr_goals,0600 ); + +static struct attribute *damos_sysfs_quota_goals_attrs[] = { + &damos_sysfs_quota_goals_nr_attr.attr, +NULL , +}; +ATTRIBUTE_GROUPS (damos_sysfs_quota_goals); + +static const struct kobj_type damos_sysfs_quota_goals_ktype = { + .release = damos_sysfs_quota_goals_release, + .sysfs_ops = &kobj_sysfs_ops, + .default_groups = damos_sysfs_quota_goals_groups, +}; +/* * scheme/weights directory */
@@ -938,6 +1135,7 @@ static const struct kobj_type damon_sysfs_weights_ktype = {struct damon_sysfs_quotas {struct kobject kobj;struct damon_sysfs_weights *weights; +struct damos_sysfs_quota_goals *goals;unsigned long ms;unsigned long sz;unsigned long reset_interval_ms;
@@ -951,6 +1149,7 @@ static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)static int damon_sysfs_quotas_add_dirs (struct damon_sysfs_quotas *quotas) {struct damon_sysfs_weights *weights; +struct damos_sysfs_quota_goals *goals;int err; weights =damon_sysfs_weights_alloc (0 ,0 ,0 );
@@ -959,16 +1158,35 @@ static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas) err =kobject_init_and_add (&weights->kobj, &damon_sysfs_weights_ktype, "as->kobj,"weights" ); -if (err) +if (err) {kobject_put (&weights->kobj); -else - quotas->weights = weights; +return err; + } + quotas->weights = weights; + + goals =damos_sysfs_quota_goals_alloc (); +if (!goals) { +kobject_put (&weights->kobj); +return -ENOMEM ; + } + err =kobject_init_and_add (&goals->kobj, + &damos_sysfs_quota_goals_ktype, "as->kobj, +"goals" ); +if (err) { +kobject_put (&weights->kobj); +kobject_put (&goals->kobj); + }else { + quotas->goals = goals; + } +return err; }static void damon_sysfs_quotas_rm_dirs (struct damon_sysfs_quotas *quotas) {kobject_put ("as->weights->kobj); +damos_sysfs_quota_goals_rm_dirs (quotas->goals); +kobject_put ("as->goals->kobj); } static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 3/9 mm/damon/sysfs-schemes: commit damos quota goals user input to DAMOS
In reply to SeongJae ParkMake DAMON sysfs interface to read the user inputs for DAMOS quota goals and pass those to DAMOS, so that the users can use the quota auto-tuning feature. It uses the DAMON sysfs interface's user input commit mechanism, which applies all user inputs for initial starting of DAMON and online input updates, which can be done by writing 'on' and 'commit' to the kdamond's 'state' file, respectively. In other words, the user should periodically write appropriate value to 'current_value' files and 'commit' command to the 'state' file. 'target_value' files could also be similarly updated at any time.
Note that the interface is supporting multiple goals while the core logic supports only one goal. DAMON sysfs interface passes only best feedback among the given inputs, to avoid making DAMOS too aggressive.
--- mm/damon/sysfs-schemes.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
mm/damon/sysfs-schemes.c +32 -0
@@ -1868,6 +1868,34 @@ static int damon_sysfs_set_scheme_filters(struct damos *scheme,return 0 ; } +static unsigned long damos_sysfs_get_quota_score (void *arg) +{ +return (unsigned long )arg; +} + +static void damos_sysfs_set_quota_score ( +struct damos_sysfs_quota_goals *sysfs_goals, +struct damos_quota *quota) +{ +struct damos_sysfs_quota_goal *sysfs_goal; +int i; + + quota->get_score =NULL ; + quota->get_score_arg = (void *)0 ; +for (i =0 ; i < sysfs_goals->nr; i++) { + sysfs_goal = sysfs_goals->goals_arr[i]; +if (!sysfs_goal->target_value) +continue ; + +/* Higher score makes scheme less aggressive */ + quota->get_score_arg = (void *)max ( + (unsigned long )quota->get_score_arg, + sysfs_goal->current_value *10000 / + sysfs_goal->target_value); + quota->get_score = damos_sysfs_get_quota_score; + } +} +static struct damos *damon_sysfs_mk_scheme (struct damon_sysfs_scheme *sysfs_scheme) {
@@ -1905,6 +1933,8 @@ static struct damos *damon_sysfs_mk_scheme( .low = sysfs_wmarks->low, }; +damos_sysfs_set_quota_score (sysfs_quotas->goals, "a); + scheme =damon_new_scheme (&pattern, sysfs_scheme->action, sysfs_scheme->apply_interval_us, "a, &wmarks);if (!scheme)
@@ -1945,6 +1975,8 @@ static void damon_sysfs_update_scheme(struct damos *scheme, scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses; scheme->quota.weight_age = sysfs_weights->age; +damos_sysfs_set_quota_score (sysfs_quotas->goals, &scheme->quota); + scheme->wmarks.metric = sysfs_wmarks->metric; scheme->wmarks.interval = sysfs_wmarks->interval_us; scheme->wmarks.high = sysfs_wmarks->high;
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 4/9 mm/damon/sysfs-schemes: implement a command for scheme quota goals only commit
In reply to SeongJae ParkTo update DAMOS quota goals, users need to enter 'commit' command to the 'state' file of the kdamond, which applies not only the goals but entire inputs. It is inefficient. Implement yet another 'state' file input command for reading and committing only the scheme quota goals, namely 'commit_schemes_quota_goals'.
--- mm/damon/sysfs-common.h | 3 +++ mm/damon/sysfs-schemes.c | 16 ++++++++++++++++ mm/damon/sysfs.c | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+)
mm/damon/sysfs-common.h +3 -0
@@ -56,3 +56,6 @@ int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx);int damon_sysfs_schemes_clear_regions (struct damon_sysfs_schemes *sysfs_schemes,struct damon_ctx *ctx); + +void damos_sysfs_set_quota_scores (struct damon_sysfs_schemes *sysfs_schemes, +struct damon_ctx *ctx);
mm/damon/sysfs-schemes.c +16 -0
@@ -1896,6 +1896,22 @@ static void damos_sysfs_set_quota_score( } } +void damos_sysfs_set_quota_scores (struct damon_sysfs_schemes *sysfs_schemes, +struct damon_ctx *ctx) +{ +struct damos *scheme; +int i =0 ; + +damon_for_each_scheme (scheme, ctx) { +struct damon_sysfs_scheme *sysfs_scheme; + + sysfs_scheme = sysfs_schemes->schemes_arr[i]; +damos_sysfs_set_quota_score (sysfs_scheme->quotas->goals, + &scheme->quota); + i++; + } +} +static struct damos *damon_sysfs_mk_scheme (struct damon_sysfs_scheme *sysfs_scheme) {
mm/damon/sysfs.c +27 -0
@@ -994,6 +994,11 @@ enum damon_sysfs_cmd {DAMON_SYSFS_CMD_OFF ,/* @DAMON_SYSFS_CMD_COMMIT: Update kdamond inputs. */ DAMON_SYSFS_CMD_COMMIT , +/* +* @DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS: Commit the quota goals +* to DAMON. +*/ + DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS,/* * @DAMON_SYSFS_CMD_UPDATE_SCHEMES_STATS: Update scheme stats sysfs * files.
@@ -1025,6 +1030,7 @@ static const char * const damon_sysfs_cmd_strs[] = {"on" ,"off" ,"commit" , +"commit_schemes_quota_goals" ,"update_schemes_stats" ,"update_schemes_tried_bytes" , "update_schemes_tried_regions",
@@ -1351,6 +1357,24 @@ static int damon_sysfs_commit_input(struct damon_sysfs_kdamond *kdamond) kdamond->contexts->contexts_arr[0]); } +static int damon_sysfs_commit_schemes_quota_goals ( +struct damon_sysfs_kdamond *sysfs_kdamond) +{ +struct damon_ctx *ctx; +struct damon_sysfs_context *sysfs_ctx; + +if (!damon_sysfs_kdamond_running (sysfs_kdamond)) +return -EINVAL ; +/* TODO: Support multiple contexts per kdamond */ +if (sysfs_kdamond->contexts->nr !=1 ) +return -EINVAL ; + + ctx = sysfs_kdamond->damon_ctx; + sysfs_ctx = sysfs_kdamond->contexts->contexts_arr[0 ]; +damos_sysfs_set_quota_scores (sysfs_ctx->schemes, ctx); +return 0 ; +} +/* * damon_sysfs_cmd_request_callback() - DAMON callback for handling requests. * @c: The DAMON context of the callback.
@@ -1379,6 +1403,9 @@ static int damon_sysfs_cmd_request_callback(struct damon_ctx *c, bool active)case DAMON_SYSFS_CMD_COMMIT : err =damon_sysfs_commit_input (kdamond);break ; +case DAMON_SYSFS_CMD_COMMIT_SCHEMES_QUOTA_GOALS : + err =damon_sysfs_commit_schemes_quota_goals (kdamond); +break ;case DAMON_SYSFS_CMD_UPDATE_SCHEMES_TRIED_BYTES : total_bytes_only = true; fallthrough;
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 5/9 mm/damon/core-test: add a unit test for the feedback loop algorithm
In reply to SeongJae ParkImplement a simple kunit test for testing the behavior of the feedback loop algorithm for the aim-oriented feedback-friven DAMOS aggressiveness auto tuning.
--- mm/damon/core-test.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
mm/damon/core-test.h +32 -0
@@ -446,6 +446,37 @@ static void damos_test_filter_out(struct kunit *test)damos_free_filter (f); } +static void damon_test_feed_loop_next_input (struct kunit *test) +{ +unsigned long last_input =900000 , current_score =200 ; + +/* +* If current score is lower than the goal, which is always 10,000 +* (read the comment on damon_feed_loop_next_input()'s comment), next +* input should be higher than the last input. +*/ +KUNIT_EXPECT_GT (test, +damon_feed_loop_next_input (last_input, current_score), + last_input); + +/* +* If current score is higher than the goal, next input should be lower +* than the last input. +*/ + current_score =250000000 ; +KUNIT_EXPECT_LT (test, +damon_feed_loop_next_input (last_input, current_score), + last_input); + +/* +* The next input depends on the distance between the current score and +* the goal +*/ +KUNIT_EXPECT_GT (test, +damon_feed_loop_next_input (last_input,200 ), +damon_feed_loop_next_input (last_input,2000 )); +} +static struct kunit_case damon_test_cases[] = {KUNIT_CASE (damon_test_target),KUNIT_CASE (damon_test_regions),
@@ -461,6 +492,7 @@ static struct kunit_case damon_test_cases[] = {KUNIT_CASE (damon_test_moving_sum),KUNIT_CASE (damos_test_new_filter),KUNIT_CASE (damos_test_filter_out), + KUNIT_CASE(damon_test_feed_loop_next_input), {}, };
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 6/9 selftests/damon: test quota goals directory
In reply to SeongJae ParkAdd DAMON selftests for testing creation/existence of quota goals directories and files, and simple valid input writes.
--- tools/testing/selftests/damon/sysfs.sh | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
tools/testing/selftests/damon/sysfs.sh +27 -0
@@ -150,6 +150,32 @@ test_weights() ensure_file "$weights_dir/age_permil" "exist" "600" } +test_goal() +{ + goal_dir=$1 + ensure_dir "$goal_dir" "exist" + ensure_file "$goal_dir/target_value" "exist" "600" + ensure_file "$goal_dir/current_value" "exist" "600" +} + +test_goals() +{ + goals_dir=$1 + ensure_dir "$goals_dir" "exist" + ensure_file "$goals_dir/nr_goals" "exist" "600" + + ensure_write_succ "$goals_dir/nr_goals" "1" "valid input" + test_goal "$goals_dir/0" + + ensure_write_succ "$goals_dir/nr_goals" "2" "valid input" + test_goal "$goals_dir/0" + test_goal "$goals_dir/1" + + ensure_write_succ "$goals_dir/nr_goals" "0" "valid input" + ensure_dir "$goals_dir/0" "not_exist" + ensure_dir "$goals_dir/1" "not_exist" +} + test_quotas() { quotas_dir=$1
@@ -158,6 +184,7 @@ test_quotas() ensure_file "$quotas_dir/bytes" "exist" 600 ensure_file "$quotas_dir/reset_interval_ms" "exist" 600 test_weights "$quotas_dir/weights" + test_goals "$quotas_dir/goals" } test_access_pattern()
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 7/9 Docs/mm/damon/design: document DAMOS quota auto tuning
In reply to SeongJae ParkDocument the DAMOS quota auto tuning feature on the design document.
--- Documentation/mm/damon/design.rst | 11 +++++++++++ 1 file changed, 11 insertions(+)
Documentation/mm/damon/design.rst +11 -0
@@ -346,6 +346,17 @@ the weight will be respected are up to the underlying prioritization mechanism implementation. +Aim-oriented Feedback-driven Auto-tuning +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Automatic feedback-driven quota tuning. Instead of setting the absolute quota +value, users can repeatedly provide numbers representing how much of their goal +for the scheme is achieved as feedback. DAMOS then automatically tunes the +aggressiveness (the quota) of the corresponding scheme. For example, if DAMOS +is under achieving the goal, DAMOS automatically increases the quota. If DAMOS +is over achieving the goal, it decreases the quota. + + .. _damon_design_damos_watermarks: Watermarks
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 8/9 Docs/ABI/damon: document DAMOS quota goals
In reply to SeongJae ParkUpdate DAMON ABI document for the newly added DAMON sysfs files and inputs for DAMOS quota goals.
--- .../ABI/testing/sysfs-kernel-mm-damon | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-)
Documentation/ABI/testing/sysfs-kernel-mm-damon +27 -6
@@ -25,12 +25,14 @@ Description: Writing 'on' or 'off' to this file makes the kdamond starts or stops, respectively. Reading the file returns the keywords based on the current status. Writing 'commit' to this file makes the kdamond reads the user inputs in the sysfs files - except 'state' again. Writing 'update_schemes_stats' to the - file updates contents of schemes stats files of the kdamond. - Writing 'update_schemes_tried_regions' to the file updates - contents of 'tried_regions' directory of every scheme directory - of this kdamond. Writing 'update_schemes_tried_bytes' to the - file updates only '.../tried_regions/total_bytes' files of this + except 'state' again. Writing 'commit_schemes_quota_goals' to + this file makes the kdamond reads the quota goal files again. + Writing 'update_schemes_stats' to the file updates contents of + schemes stats files of the kdamond. Writing + 'update_schemes_tried_regions' to the file updates contents of + 'tried_regions' directory of every scheme directory of this + kdamond. Writing 'update_schemes_tried_bytes' to the file + updates only '.../tried_regions/total_bytes' files of this kdamond. Writing 'clear_schemes_tried_regions' to the file removes contents of the 'tried_regions' directory.
@@ -212,6 +214,25 @@ Contact: SeongJae Park <[email protected]> Description: Writing to and reading from this file sets and gets the quotas charge reset interval of the scheme in milliseconds. +What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/nr_goals +Date: Nov 2023 +Contact: SeongJae Park <[email protected]> +Description: Writing a number 'N' to this file creates the number of + directories for setting automatic tuning of the scheme's + aggressiveness named '0' to 'N-1' under the goals/ directory. + +What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/target_value +Date: Nov 2023 +Contact: SeongJae Park <[email protected]> +Description: Writing to and reading from this file sets and gets the target + value of the goal metric. + +What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/current_value +Date: Nov 2023 +Contact: SeongJae Park <[email protected]> +Description: Writing to and reading from this file sets and gets the current + value of the goal metric. + What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/weights/sz_permil Date: Mar 2022 Contact: SeongJae Park <[email protected]>
Signature · 1 line
2.34.1
SeongJae Park
maintainerPATCH 9/9 Docs/admin-guide/mm/damon/usage: document for quota goals
In reply to SeongJae ParkUpdate DAMON sysfs usage for newly added DAMOS quota goals interface.
--- Documentation/admin-guide/mm/damon/usage.rst | 48 +++++++++++++++++--- Documentation/mm/damon/design.rst | 2 + 2 files changed, 43 insertions(+), 7 deletions(-)
Documentation/admin-guide/mm/damon/usage.rst +41 -7
@@ -83,6 +83,8 @@ comma (","). :: │ │ │ │ │ │ │ │ age/min,max │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms │ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil + │ │ │ │ │ │ │ │ goals/nr_goals + │ │ │ │ │ │ │ │ │ 0/target_value,current_value │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low │ │ │ │ │ │ │ filters/nr_filters │ │ │ │ │ │ │ │ 0/type,matching,memcg_id
@@ -113,6 +115,8 @@ details) exists. In the beginning, this directory has only one file, child directories named ``0`` to ``N-1``. Each directory represents each kdamond. +.. _sysfs_kdamond: + kdamonds/<N>/ -------------
@@ -121,11 +125,18 @@ In each kdamond directory, two files (``state`` and ``pid``) and one directory Reading ``state`` returns ``on`` if the kdamond is currently running, or ``off`` if it is not running. Writing ``on`` or ``off`` makes the kdamond be -in the state. Writing ``commit`` to the ``state`` file makes kdamond reads the +in the state. + +Writing ``commit`` to the ``state`` file makes kdamond reads the user inputs in the sysfs files except ``state`` file again. Writing -``update_schemes_stats`` to ``state`` file updates the contents of stats files -for each DAMON-based operation scheme of the kdamond. For details of the -stats, please refer to :ref:`stats section <sysfs_schemes_stats>`. +``commit_schemes_quota_goals`` to the ``state`` file makes kdamond reads the +DAMON-based operation schemes' :ref:`quota goals <sysfs_schemes_quota_goals>` +of the kdamond. + +Writing ``update_schemes_stats`` to ``state`` file updates the +contents of stats files for each DAMON-based operation scheme of the kdamond. +For details of the stats, please refer to :ref:`stats section +<sysfs_schemes_stats>`. Writing ``update_schemes_tried_regions`` to ``state`` file updates the DAMON-based operation scheme action tried regions directory for each
@@ -319,8 +330,7 @@ The directory for the :ref:`quotas <damon_design_damos_quotas>` of the given DAMON-based operation scheme. Under ``quotas`` directory, three files (``ms``, ``bytes``, -``reset_interval_ms``) and one directory (``weights``) having three files -(``sz_permil``, ``nr_accesses_permil``, and ``age_permil``) in it exist. +``reset_interval_ms``) and two directores (``weights`` and ``goals``) exist. You can set the ``time quota`` in milliseconds, ``size quota`` in bytes, and ``reset interval`` in milliseconds by writing the values to the three files,
@@ -330,11 +340,35 @@ apply the action to only up to ``bytes`` bytes of memory regions within the ``reset_interval_ms``. Setting both ``ms`` and ``bytes`` zero disables the quota limits. -You can also set the :ref:`prioritization weights +Under ``weights`` directory, three files (``sz_permil``, +``nr_accesses_permil``, and ``age_permil``) exist. +You can set the :ref:`prioritization weights <damon_design_damos_quotas_prioritization>` for size, access frequency, and age in per-thousand unit by writing the values to the three files under the ``weights`` directory. +.. _sysfs_schemes_quota_goals: + +schemes/<N>/quotas/goals/ +------------------------- + +The directory for the :ref:`automatic quota tuning goals +<damon_design_damos_quotas_auto_tuning>` of the given DAMON-based operation +scheme. + +In the beginning, this directory has only one file, ``nr_goals``. Writing a +number (``N``) to the file creates the number of child directories named ``0`` +to ``N-1``. Each directory represents each goal and current achievement. +Among the multiple feedback, the best one is used. + +Each goal directory contains two files, namely ``target_value`` and +``current_value``. Users can set and get any number to those files to set the +feedback. User space main workload's latency or throughput, system metrics +like free memory ratio or memory pressure stall time (PSI) could be example +metrics for the values. Note that users should write +``commit_schemes_quota_goals`` to the ``state`` file of the :ref:`kdamond +directory <sysfs_kdamond>` to pass the feedback to DAMON. + schemes/<N>/watermarks/ -----------------------
Documentation/mm/damon/design.rst +2 -0
@@ -346,6 +346,8 @@ the weight will be respected are up to the underlying prioritization mechanism implementation. +.. _damon_design_damos_quotas_auto_tuning: + Aim-oriented Feedback-driven Auto-tuning ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Signature · 1 line
2.34.1
Andrew Morton
maintainerQuoted 9 lines · On Thu, 30 Nov 2023 02:36:43 +0000 SeongJae Park <[email protected]> wrote:
The core logic uses the below simple feedback loop algorithm to calculate the next aggressiveness level of the scheme from the current aggressiveness level and the current feedback (
target_scoreandcurrent_score). It calculates the compensation for next aggressiveness as a proportion of current aggressiveness and distance to the target score. As a result, it arrives at the near-goal state in a short time using big steps when it's far from the goal, but avoids making unnecessarily radical changes that could turn out to be a bad decision using small steps when its near to the goal.
fwiw, the above is a "proportional controller". MGLRU has, in vmscan.c, a PID controller (proportional, integral, derivative). PID controllers have better accuracy (the integral feedback) and better stability (the derivative feedback).
Generalizing MGLRU's PID controller might be somewhat challenging!