cgroup-aware OOM killer
Subsystems (5)
v8 cover cgroup-aware OOM killer
This patchset makes the OOM killer cgroup-aware.
v8:
- Do not kill tasks with OOM_SCORE_ADJ -1000
- Make the whole thing opt-in with cgroup mount option control
- Drop oom_priority for further discussions
- Kill the whole cgroup if oom_group is set and it's memory.max is reached
- Update docs and commit messages
v7:
- __oom_kill_process() drops reference to the victim task
- oom_score_adj -1000 is always respected
- Renamed oom_kill_all to oom_group
- Dropped oom_prio range, converted from short to int
- Added a cgroup v2 mount option to disable cgroup-aware OOM killer
- Docs updated
- Rebased on top of mmotm
v6:
- Renamed oom_control.chosen to oom_control.chosen_task
- Renamed oom_kill_all_tasks to oom_kill_all
- Per-node NR_SLAB_UNRECLAIMABLE accounting
- Several minor fixes and cleanups
- Docs updated
v5:
- Rebased on top of Michal Hocko's patches, which have changed the way how OOM victims becoming an access to the memory reserves. Dropped corresponding part of this patchset
- Separated the oom_kill_process() splitting into a standalone commit
- Added debug output (suggested by David Rientjes)
- Some minor fixes
v4:
- Reworked per-cgroup oom_score_adj into oom_priority (based on ideas by David Rientjes)
- Tasks with oom_score_adj -1000 are never selected if oom_kill_all_tasks is not set
- Memcg victim selection code is reworked, and synchronization is based on finding tasks with OOM victim marker, rather then on global counter
- Debug output is dropped
- Refactored TIF_MEMDIE usage
v3:
- Merged commits 1-4 into 6
- Separated oom_score_adj logic and debug output into separate commits
- Fixed swap accounting
v2:
- Reworked victim selection based on feedback
from Michal Hocko, Vladimir Davydov and Johannes Weiner
- "Kill all tasks" is now an opt-in option, by default only one process will be killed
- Added per-cgroup oom_score_adj
- Refined oom score calculations, suggested by Vladimir Davydov
- Converted to a patchset
v1:
https://lkml.org/lkml/2017/5/18/969
Roman Gushchin (4):
mm, oom: refactor the oom_kill_process() function
mm, oom: cgroup-aware OOM killer
mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer mm, oom, docs: describe the cgroup-aware OOM killer
Documentation/cgroup-v2.txt | 39 +++++++ include/linux/cgroup-defs.h | 5 + include/linux/memcontrol.h | 33 ++++++ include/linux/oom.h | 12 +- kernel/cgroup/cgroup.c | 10 ++ mm/memcontrol.c | 261 ++++++++++++++++++++++++++++++++++++++++++++ mm/oom_kill.c | 210 +++++++++++++++++++++++------------ 7 files changed, 501 insertions(+), 69 deletions(-)
Signature · 7 lines
2.13.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v8 1/4 mm, oom: refactor the oom_kill_process() function
The oom_kill_process() function consists of two logical parts:
the first one is responsible for considering task's children as a potential victim and printing the debug information. The second half is responsible for sending SIGKILL to all tasks sharing the mm struct with the given victim.
This commit splits the oom_kill_process() function with an intention to re-use the the second half: __oom_kill_process().
The cgroup-aware OOM killer will kill multiple tasks belonging to the victim cgroup. We don't need to print the debug information for the each task, as well as play with task selection (considering task's children), so we can't use the existing oom_kill_process().
--- mm/oom_kill.c | 123 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 58 deletions(-)
mm/oom_kill.c +65 -58
@@ -804,68 +804,12 @@ static bool task_will_free_mem(struct task_struct *task)return ret; } -static void oom_kill_process (struct oom_control *oc,const char *message) +static void __oom_kill_process (struct task_struct *victim) { -struct task_struct *p = oc->chosen; -unsigned int points = oc->chosen_points; -struct task_struct *victim = p; -struct task_struct *child; -struct task_struct *t; +struct task_struct *p;struct mm_struct *mm; -unsigned int victim_points =0 ; - static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST);bool can_oom_reap = true; -/* -* If the task is already exiting, don't alarm the sysadmin or kill -* its children or threads, just give it access to memory reserves -* so it can die quickly -*/ -task_lock (p); -if (task_will_free_mem (p)) { -mark_oom_victim (p); -wake_oom_reaper (p); -task_unlock (p); -put_task_struct (p); -return ; - } -task_unlock (p); - -if (__ratelimit (&oom_rs)) -dump_header (oc, p); - -pr_err ("%s: Kill process %d (%s) score %u or sacrifice child\n" , - message,task_pid_nr (p), p->comm, points); - -/* -* If any of p's children has a different mm and is eligible for kill, -* the one with the highest oom_badness() score is sacrificed for its -* parent. This attempts to lose the minimal amount of work done while -* still freeing memory. -*/ -read_lock (&tasklist_lock); -for_each_thread (p, t) { -list_for_each_entry (child, &t->children, sibling) { -unsigned int child_points; - -if (process_shares_mm (child, p->mm)) -continue ; -/* -* oom_badness() returns 0 if the thread is unkillable -*/ - child_points =oom_badness (child, - oc->memcg, oc->nodemask, oc->totalpages); -if (child_points > victim_points) { -put_task_struct (victim); - victim = child; - victim_points = child_points; -get_task_struct (victim); - } - } - } -read_unlock (&tasklist_lock); - p =find_lock_task_mm (victim);if (!p) {put_task_struct (victim);
@@ -939,6 +883,69 @@ static void oom_kill_process(struct oom_control *oc, const char *message) }#undef K +static void oom_kill_process (struct oom_control *oc,const char *message) +{ +struct task_struct *p = oc->chosen; +unsigned int points = oc->chosen_points; +struct task_struct *victim = p; +struct task_struct *child; +struct task_struct *t; +unsigned int victim_points =0 ; + static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + +/* +* If the task is already exiting, don't alarm the sysadmin or kill +* its children or threads, just give it access to memory reserves +* so it can die quickly +*/ +task_lock (p); +if (task_will_free_mem (p)) { +mark_oom_victim (p); +wake_oom_reaper (p); +task_unlock (p); +put_task_struct (p); +return ; + } +task_unlock (p); + +if (__ratelimit (&oom_rs)) +dump_header (oc, p); + +pr_err ("%s: Kill process %d (%s) score %u or sacrifice child\n" , + message,task_pid_nr (p), p->comm, points); + +/* +* If any of p's children has a different mm and is eligible for kill, +* the one with the highest oom_badness() score is sacrificed for its +* parent. This attempts to lose the minimal amount of work done while +* still freeing memory. +*/ +read_lock (&tasklist_lock); +for_each_thread (p, t) { +list_for_each_entry (child, &t->children, sibling) { +unsigned int child_points; + +if (process_shares_mm (child, p->mm)) +continue ; +/* +* oom_badness() returns 0 if the thread is unkillable +*/ + child_points =oom_badness (child, + oc->memcg, oc->nodemask, oc->totalpages); +if (child_points > victim_points) { +put_task_struct (victim); + victim = child; + victim_points = child_points; +get_task_struct (victim); + } + } + } +read_unlock (&tasklist_lock); + +__oom_kill_process (victim); +} +/* * Determines whether the kernel must panic because of the panic_on_oom sysctl. */
Signature · 7 lines
2.13.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [v8 1/4] mm, oom: refactor the oom_kill_process() function
Quoted 15 lines · Roman Gushchin
The
oom_kill_process()function consists of two logical parts:
the first one is responsible for considering task's children as a potential victim and printing the debug information. The second half is responsible for sending SIGKILL to all tasks sharing the mm struct with the given victim.This commit splits the
oom_kill_process()function with an intention to re-use the the second half:__oom_kill_process().The cgroup-aware OOM killer will kill multiple tasks belonging to the victim cgroup. We don't need to print the debug information for the each task, as well as play with task selection (considering task's children), so we can't use the existing
oom_kill_process().
Quoted 13 lines
Signed-off-by Roman Gushchin <[email protected]>Cc Michal Hocko <[email protected]>Cc Vladimir Davydov <[email protected]>Cc Johannes Weiner <[email protected]>Cc Tetsuo Handa <[email protected]>Cc David Rientjes <[email protected]>Cc Andrew Morton <[email protected]>Cc Tejun Heo <[email protected]>
Re: [v8 1/4] mm, oom: refactor the oom_kill_process() function
In reply to Roman GushchinQuoted 15 lines · Roman Gushchin
The
oom_kill_process()function consists of two logical parts:
the first one is responsible for considering task's children as a potential victim and printing the debug information. The second half is responsible for sending SIGKILL to all tasks sharing the mm struct with the given victim.This commit splits the
oom_kill_process()function with an intention to re-use the the second half:__oom_kill_process().The cgroup-aware OOM killer will kill multiple tasks belonging to the victim cgroup. We don't need to print the debug information for the each task, as well as play with task selection (considering task's children), so we can't use the existing
oom_kill_process().
Quoted 13 lines
Signed-off-by Roman Gushchin <[email protected]>Cc Michal Hocko <[email protected]>Cc Vladimir Davydov <[email protected]>Cc Johannes Weiner <[email protected]>Cc Tetsuo Handa <[email protected]>Cc David Rientjes <[email protected]>Cc Andrew Morton <[email protected]>Cc Tejun Heo <[email protected]>
Quoted 151 lines
--- mm/oom_kill.c | 123 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 58 deletions(-)mm/oom_kill.c +65
-58@@ -804,68 +804,12 @@ static bool task_will_free_mem(struct task_struct *task)return ret; } -static void oom_kill_process (struct oom_control *oc,const char *message) +static void __oom_kill_process (struct task_struct *victim) { -struct task_struct *p = oc->chosen; -unsigned int points = oc->chosen_points; -struct task_struct *victim = p; -struct task_struct *child; -struct task_struct *t; +struct task_struct *p;struct mm_struct *mm; -unsigned int victim_points =0 ; - static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST);bool can_oom_reap = true; -/* -* If the task is already exiting, don't alarm the sysadmin or kill -* its children or threads, just give it access to memory reserves -* so it can die quickly -*/ -task_lock (p); -if (task_will_free_mem (p)) { -mark_oom_victim (p); -wake_oom_reaper (p); -task_unlock (p); -put_task_struct (p); -return ; - } -task_unlock (p); - -if (__ratelimit (&oom_rs)) -dump_header (oc, p); - -pr_err ("%s: Kill process %d (%s) score %u or sacrifice child\n" , - message,task_pid_nr (p), p->comm, points); - -/* -* If any of p's children has a different mm and is eligible for kill, -* the one with the highest oom_badness() score is sacrificed for its -* parent. This attempts to lose the minimal amount of work done while -* still freeing memory. -*/ -read_lock (&tasklist_lock); -for_each_thread (p, t) { -list_for_each_entry (child, &t->children, sibling) { -unsigned int child_points; - -if (process_shares_mm (child, p->mm)) -continue ; -/* -* oom_badness() returns 0 if the thread is unkillable -*/ - child_points =oom_badness (child, - oc->memcg, oc->nodemask, oc->totalpages); -if (child_points > victim_points) { -put_task_struct (victim); - victim = child; - victim_points = child_points; -get_task_struct (victim); - } - } - } -read_unlock (&tasklist_lock); - p =find_lock_task_mm (victim);if (!p) {put_task_struct (victim);@@ -939,6 +883,69 @@ static void oom_kill_process(struct oom_control *oc, const char *message) }#undef K +static void oom_kill_process (struct oom_control *oc,const char *message) +{ +struct task_struct *p = oc->chosen; +unsigned int points = oc->chosen_points; +struct task_struct *victim = p; +struct task_struct *child; +struct task_struct *t; +unsigned int victim_points =0 ; + static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + +/* +* If the task is already exiting, don't alarm the sysadmin or kill +* its children or threads, just give it access to memory reserves +* so it can die quickly +*/ +task_lock (p); +if (task_will_free_mem (p)) { +mark_oom_victim (p); +wake_oom_reaper (p); +task_unlock (p); +put_task_struct (p); +return ; + } +task_unlock (p); + +if (__ratelimit (&oom_rs)) +dump_header (oc, p); + +pr_err ("%s: Kill process %d (%s) score %u or sacrifice child\n" , + message,task_pid_nr (p), p->comm, points); + +/* +* If any of p's children has a different mm and is eligible for kill, +* the one with the highest oom_badness() score is sacrificed for its +* parent. This attempts to lose the minimal amount of work done while +* still freeing memory. +*/ +read_lock (&tasklist_lock); +for_each_thread (p, t) { +list_for_each_entry (child, &t->children, sibling) { +unsigned int child_points; + +if (process_shares_mm (child, p->mm)) +continue ; +/* +* oom_badness() returns 0 if the thread is unkillable +*/ + child_points =oom_badness (child, + oc->memcg, oc->nodemask, oc->totalpages); +if (child_points > victim_points) { +put_task_struct (victim); + victim = child; + victim_points = child_points; +get_task_struct (victim); + } + } + } +read_unlock (&tasklist_lock); + +__oom_kill_process (victim); +} +/* * Determines whether the kernel must panic because of the panic_on_oom sysctl. */ Signature · 1 line
2.13.5
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v8 2/4 mm, oom: cgroup-aware OOM killer
In reply to Roman GushchinTraditionally, the OOM killer is operating on a process level. Under oom conditions, it finds a process with the highest oom score and kills it.
This behavior doesn't suit well the system with many running containers:
1) There is no fairness between containers. A small container with few large processes will be chosen over a large one with huge number of small processes.
2) Containers often do not expect that some random process inside will be killed. In many cases much safer behavior is to kill all tasks in the container. Traditionally, this was implemented in userspace, but doing it in the kernel has some advantages, especially in a case of a system-wide OOM.
To address these issues, the cgroup-aware OOM killer is introduced.
Under OOM conditions, it looks for the biggest memory consumer, walking down by the memcg tree from root cgroup or OOMing cgroup, if OOM is caused by reaching memcg memory limit. On each level the memcg with biggest memory footprint is selected.
By default, a leaf memcg is chosen, and the biggest task inside is killed.
But a user can change this behavior by enabling the per-cgroup memory.oom_group option. If set, it causes the OOM killer to treat the whole cgroup as an indivisible memory consumer. This means that OOM victim selection will stop at such memcg, the whole memcg will be selected, and all belonging tasks will be killed. The only exception is tasks with oom_score_adj set to -1000 are considered as unkillable.
The root cgroup is treated as a leaf memcg, so it's score is compared with top-level memory cgroups. The oom_group option is not supported for the root cgroup. Due to memcg statistics implementation a special algorithm is used for estimating root cgroup oom_score: we define it as maximum oom_score of the belonging tasks.
--- include/linux/memcontrol.h | 33 ++++++ include/linux/oom.h | 12 ++- mm/memcontrol.c | 258 +++++++++++++++++++++++++++++++++++++++++++++ mm/oom_kill.c | 95 ++++++++++++++--- 4 files changed, 383 insertions(+), 15 deletions(-)
include/linux/memcontrol.h +33 -0
@@ -35,6 +35,7 @@ struct mem_cgroup;struct page ;struct mm_struct ;struct kmem_cache ; +struct oom_control ;/* Cgroup-specific page state, on top of universal node page state */ enum memcg_stat_item {
@@ -199,6 +200,12 @@ struct mem_cgroup {/* OOM-Killer disable */ int oom_kill_disable; +/* kill all tasks in the subtree in case of OOM */ +bool oom_group; + +/* cached OOM score */ +long oom_score; +/* handle for "memory.events" */ struct cgroup_file events_file;
@@ -342,6 +349,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){ return css ? container_of(css, struct mem_cgroup, css) : NULL; } +static inline void mem_cgroup_put (struct mem_cgroup *memcg) +{ +css_put (&memcg->css); +} +#define mem_cgroup_from_counter (counter, member) \ container_of(counter, struct mem_cgroup, member)
@@ -480,6 +492,13 @@ static inline bool task_in_memcg_oom(struct task_struct *p)bool mem_cgroup_oom_synchronize (bool wait); +bool mem_cgroup_select_oom_victim (struct oom_control *oc); + +static inline bool mem_cgroup_oom_group (struct mem_cgroup *memcg) +{ +return memcg->oom_group; +} +#ifdef CONFIG_MEMCG_SWAP extern int do_swap_account;#endif
@@ -744,6 +763,10 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,return true; } +static inline void mem_cgroup_put (struct mem_cgroup *memcg) +{ +} +static inline struct mem_cgroup * mem_cgroup_iter(struct mem_cgroup *root, struct mem_cgroup *prev,
@@ -936,6 +959,16 @@ static inlinevoid count_memcg_event_mm (struct mm_struct *mm,enum vm_event_item idx) { } + +static inline bool mem_cgroup_select_oom_victim (struct oom_control *oc) +{ +return false; +} + +static inline bool mem_cgroup_oom_group (struct mem_cgroup *memcg) +{ +return false; +}#endif /* CONFIG_MEMCG */ /* idx can be of type enum memcg_stat_item or node_stat_item */
include/linux/oom.h +11 -1
@@ -9,6 +9,13 @@#include <linux/sched/coredump.h> /* MMF_* */ #include <linux/mm.h> /* VM_FAULT* */ + +/* +* Special value returned by victim selection functions to indicate +* that are inflight OOM victims. +*/ +#define INFLIGHT_VICTIM ((void *)-1UL) +struct zonelist ;struct notifier_block ;struct mem_cgroup ;
@@ -39,7 +46,8 @@ struct oom_control {/* Used by oom implementation, do not set */ unsigned long totalpages; -struct task_struct *chosen; +struct task_struct *chosen_task; +struct mem_cgroup *chosen_memcg;unsigned long chosen_points; };
@@ -101,6 +109,8 @@ extern void oom_killer_enable(void);extern struct task_struct *find_lock_task_mm (struct task_struct *p); +extern int oom_evaluate_task (struct task_struct *task,void *arg); +/* sysctls */ extern int sysctl_oom_dump_tasks;extern int sysctl_oom_kill_allocating_task;
mm/memcontrol.c +258 -0
276 lines not on this page · raw message
mm/oom_kill.c +81 -14
158 lines not on this page · raw message
Signature · 7 lines
2.13.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerRe: [v8 2/4] mm, oom: cgroup-aware OOM killer
Quoted 21 lines · Roman Gushchin
mm/memcontrol.c +13
-0@@ -2661,6 +2661,231 @@ static inline bool memcg_has_children(struct mem_cgroup *memcg)return ret; } +static long memcg_oom_badness (struct mem_cgroup *memcg, +const nodemask_t *nodemask, +unsigned long totalpages) +{ +long points =0 ; +int nid; +pg_data_t *pgdat; + +/* +* We don't have necessary stats for the root memcg, +* so we define it's oom_score as the maximum oom_score +* of the belonging tasks. +*/
mm/memcontrol.c static inline bool memcg_has_children(struct mem_cgroup *memcg) · line 2686
Quoted 10 lines
mm/memcontrol.c +10
-0+if (memcg == root_mem_cgroup) { +struct css_task_iter it; +struct task_struct *task; +long score, max_score =0 ; + +css_task_iter_start (&memcg->css,0 , &it); +while ((task =css_task_iter_next (&it))) { + score =oom_badness (task, memcg, nodemask, + totalpages); +if (max_score > score)
score > max_score
Quoted 26 lines
mm/memcontrol.c +26
-0+ max_score = score; + } +css_task_iter_end (&it); + +return max_score; + } + +for_each_node_state (nid,N_MEMORY ) { +if (nodemask && !node_isset (nid, *nodemask)) +continue ; + + points +=mem_cgroup_node_nr_lru_pages (memcg, nid, +LRU_ALL_ANON |BIT (LRU_UNEVICTABLE )); + + pgdat =NODE_DATA (nid); + points +=lruvec_page_state (mem_cgroup_lruvec (pgdat, memcg), +NR_SLAB_UNRECLAIMABLE ); + } + + points +=memcg_page_state (memcg,MEMCG_KERNEL_STACK_KB ) / + (PAGE_SIZE /1024 ); + points +=memcg_page_state (memcg,MEMCG_SOCK ); + points +=memcg_page_state (memcg,MEMCG_SWAP ); + +return points; +}
Re: [v8 2/4] mm, oom: cgroup-aware OOM killer
Quoted 27 lines · David Rientjes
Quoted 25 lines · Roman Gushchin
mm/memcontrol.c +17
-0@@ -2661,6 +2661,231 @@ static inline bool memcg_has_children(struct mem_cgroup *memcg)return ret; } +static long memcg_oom_badness (struct mem_cgroup *memcg, +const nodemask_t *nodemask, +unsigned long totalpages) +{ +long points =0 ; +int nid; +pg_data_t *pgdat; + +/* +* We don't have necessary stats for the root memcg, +* so we define it's oom_score as the maximum oom_score +* of the belonging tasks. +*/ +if (memcg == root_mem_cgroup) { +struct css_task_iter it; +struct task_struct *task; +long score, max_score =0 ;
Quoted 8 lines
mm/memcontrol.c static inline bool memcg_has_children(struct mem_cgroup *memcg) · line 2686
Quoted 6 lines
mm/memcontrol.c +6
-0+ +css_task_iter_start (&memcg->css,0 , &it); +while ((task =css_task_iter_next (&it))) { + score =oom_badness (task, memcg, nodemask, + totalpages); +if (max_score > score)score >
max_score
Ups. Fixed. Thanks!
PATCH v8 3/4 mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer
In reply to Roman GushchinAdd a "groupoom" cgroup v2 mount option to enable the cgroup-aware OOM killer. If not set, the OOM selection is performed in a "traditional" per-process way.
The behavior can be changed dynamically by remounting the cgroupfs.
--- include/linux/cgroup-defs.h | 5 +++++ kernel/cgroup/cgroup.c | 10 ++++++++++ mm/memcontrol.c | 3 +++ 3 files changed, 18 insertions(+)
include/linux/cgroup-defs.h +5 -0
@@ -79,6 +79,11 @@ enum {* Enable cpuset controller in v1 cgroup to use v2 behavior. */ CGRP_ROOT_CPUSET_V2_MODE = (1 <<4 ), + +/* +* Enable cgroup-aware OOM killer. +*/ + CGRP_GROUP_OOM = (1 << 5), };/* cftype->flags */
kernel/cgroup/cgroup.c +10 -0
@@ -1699,6 +1699,9 @@ static int parse_cgroup_root_flags(char *data, unsigned int *root_flags)if (!strcmp (token,"nsdelegate" )) { *root_flags |=CGRP_ROOT_NS_DELEGATE ;continue ; + }else if (!strcmp (token,"groupoom" )) { + *root_flags |=CGRP_GROUP_OOM ; +continue ; }pr_err ("cgroup2: unknown option \"%s\"\n" , token);
@@ -1715,6 +1718,11 @@ static void apply_cgroup_root_flags(unsigned int root_flags) cgrp_dfl_root.flags |=CGRP_ROOT_NS_DELEGATE ; else cgrp_dfl_root.flags &= ~CGRP_ROOT_NS_DELEGATE; + +if (root_flags &CGRP_GROUP_OOM ) + cgrp_dfl_root.flags |=CGRP_GROUP_OOM ; +else + cgrp_dfl_root.flags &= ~CGRP_GROUP_OOM ; } }
@@ -1722,6 +1730,8 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root {if (cgrp_dfl_root.flags &CGRP_ROOT_NS_DELEGATE )seq_puts (seq,",nsdelegate" ); +if (cgrp_dfl_root.flags &CGRP_GROUP_OOM ) +seq_puts (seq,",groupoom" );return 0 ; }
mm/memcontrol.c +3 -0
@@ -2871,6 +2871,9 @@ bool mem_cgroup_select_oom_victim(struct oom_control *oc)if (!cgroup_subsys_on_dfl (memory_cgrp_subsys))return false; +if (!(cgrp_dfl_root.flags &CGRP_GROUP_OOM )) +return false; +if (oc->memcg) root = oc->memcg;else
Signature · 1 line
2.13.5
David Rientjes
reviewerRe: [v8 3/4] mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer
Quoted 5 lines · Roman Gushchin
Add a "groupoom" cgroup v2 mount option to enable the cgroup-aware OOM killer. If not set, the OOM selection is performed in a "traditional" per-process way.
The behavior can be changed dynamically by remounting the cgroupfs.
I can't imagine that Tejun would be happy with a new mount option, especially when it's not required.
OOM behavior does not need to be defined at mount time and for the entire hierarchy. It's possible to very easily implement a tunable as part of mem cgroup that is propagated to descendants and controls the oom scoring behavior for that hierarchy. It does not need to be system wide and affect scoring of all processes based on which mem cgroup they are attached to at any given time.
Re: [v8 3/4] mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer
Quoted 11 lines · David Rientjes
Quoted 5 lines · Roman Gushchin
Add a "groupoom" cgroup v2 mount option to enable the cgroup-aware OOM killer. If not set, the OOM selection is performed in a "traditional" per-process way.
The behavior can be changed dynamically by remounting the cgroupfs.
I can't imagine that Tejun would be happy with a new mount option, especially when it's not required.
Quoted 6 lines
OOM behavior does not need to be defined at mount time and for the entire hierarchy. It's possible to very easily implement a tunable as part of mem cgroup that is propagated to descendants and controls the oom scoring behavior for that hierarchy. It does not need to be system wide and affect scoring of all processes based on which mem cgroup they are attached to at any given time.
No, I don't think that mixing per-cgroup and per-process OOM selection algorithms is a good idea.
So, there are 3 reasonable options:
1) boot option
2) sysctl
3) cgroup mount option
I believe, 3) is better, because it allows changing the behavior dynamically, and explicitly depends on v2 (what sysctl lacks).
So, the only question is should it be opt-in or opt-out option. Personally, I would prefer opt-out, but Michal has a very strong opinion here.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerRe: [v8 3/4] mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer
Quoted 18 lines · Roman Gushchin
Quoted 9 lines
I can't imagine that Tejun would be happy with a new mount option, especially when it's not required.
OOM behavior does not need to be defined at mount time and for the entire hierarchy. It's possible to very easily implement a tunable as part of mem cgroup that is propagated to descendants and controls the oom scoring behavior for that hierarchy. It does not need to be system wide and affect scoring of all processes based on which mem cgroup they are attached to at any given time.
No, I don't think that mixing per-cgroup and per-process OOM selection algorithms is a good idea.
So, there are 3 reasonable options:
1) boot option
2) sysctl
3) cgroup mount option
Quoted 6 lines
I believe, 3) is better, because it allows changing the behavior dynamically, and explicitly depends on v2 (what sysctl lacks).
So, the only question is should it be opt-in or opt-out option. Personally, I would prefer opt-out, but Michal has a very strong opinion here.
If it absolutely must be a mount option, then I would agree it should be opt-in so that it's known what is being changed rather than changing how selection was done in the past and requiring legacy users to now mount in a new way.
I'd be interested to hear Tejun's comments, however, about whether we want to add controller specific mount options like this instead of a tunable at the root level, for instance, that controls victim selection and would be isolated to the memory cgroup controller as opposed to polluting mount options.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerRe: [v8 3/4] mm, oom: add cgroup v2 mount option for cgroup-aware OOM killer
In reply to Roman GushchinQuoted 22 lines · Roman Gushchin
Quoted 11 lines · David Rientjes
Quoted 5 lines · Roman Gushchin
Add a "groupoom" cgroup v2 mount option to enable the cgroup-aware OOM killer. If not set, the OOM selection is performed in a "traditional" per-process way.
The behavior can be changed dynamically by remounting the cgroupfs.
I can't imagine that Tejun would be happy with a new mount option, especially when it's not required.
Quoted 6 lines
OOM behavior does not need to be defined at mount time and for the entire hierarchy. It's possible to very easily implement a tunable as part of mem cgroup that is propagated to descendants and controls the oom scoring behavior for that hierarchy. It does not need to be system wide and affect scoring of all processes based on which mem cgroup they are attached to at any given time.
No, I don't think that mixing per-cgroup and per-process OOM selection algorithms is a good idea.
Quoted 7 lines
So, there are 3 reasonable options:
1) boot option
2) sysctl
3) cgroup mount optionI believe, 3) is better, because it allows changing the behavior dynamically, and explicitly depends on v2 (what sysctl lacks).
I see your argument here. I would just be worried that we end up really needing more oom strategies in future and those wouldn't fit into memcg mount option scope. So 1/2 sounds more exensible to me long term. Boot time would be easier because we do not have to bother dynamic selection in that case.
Quoted 2 lines
So, the only question is should it be opt-in or opt-out option. Personally, I would prefer opt-out, but Michal has a very strong opinion here.
Yes I still strongly believe this has to be opt-in.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v8 4/4 mm, oom, docs: describe the cgroup-aware OOM killer
In reply to Roman GushchinDocument the cgroup-aware OOM killer.
--- Documentation/cgroup-v2.txt | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
Documentation/cgroup-v2.txt +39 -0
@@ -48,6 +48,7 @@ v1 is available under Documentation/cgroup-v1/. 5-2-1. Memory Interface Files 5-2-2. Usage Guidelines 5-2-3. Memory Ownership + 5-2-4. OOM Killer 5-3. IO 5-3-1. IO Interface Files 5-3-2. Writeback
@@ -1034,6 +1035,18 @@ PAGE_SIZE multiple when read back. high limit is used and monitored properly, this limit's utility is limited to providing the final safety net. + memory.oom_group + + A read-write single value file which exists on non-root + cgroups. The default is "0". + + If set, OOM killer will kill all processes attached to the cgroup + if selected as an OOM victim. + + OOM killer respects the /proc/pid/oom_score_adj value -1000, + and will never kill the unkillable task, even if memory.oom_group + is set. + memory.events A read-only flat-keyed file which exists on non-root cgroups. The following entries are defined. Unless specified
@@ -1237,6 +1250,32 @@ to be accessed repeatedly by other cgroups, it may make sense to use POSIX_FADV_DONTNEED to relinquish the ownership of memory areas belonging to the affected files to ensure correct memory ownership. +OOM Killer +~~~~~~~~~~ + +Cgroup v2 memory controller implements a cgroup-aware OOM killer. +It means that it treats cgroups as first class OOM entities. + +Under OOM conditions the memory controller tries to make the best +choice of a victim, hierarchically looking for a cgroup with the +largest memory footprint. + +By default, OOM killer will kill the biggest task in the selected +memory cgroup. A user can change this behavior by enabling +the per-cgroup oom_group option. If set, it causes the OOM killer +to kill all processes attached to the cgroup, except processes +with oom_score_adj set to -1000. + +This affects both system- and cgroup-wide OOMs. For a cgroup-wide OOM +the memory controller considers only cgroups belonging to the sub-tree +of the OOM'ing cgroup. + +The root cgroup is treated as a leaf memory cgroup, so it's compared +with top-level memory cgroups. + +If there are no cgroups with the enabled memory controller, +the OOM killer is using the "traditional" process-based approach. + IO --
Signature · 7 lines
2.13.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Roman Gushchin
This patchset makes the OOM killer cgroup-aware.
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussions
Nack, we specifically require oom_priority for this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required. v8 appears to implement new functionality that we want, to compare two memcgs based on usage, but without the ability to influence that decision to protect important userspace, so now I'm in a position where (1) nothing has changed if I don't use the new mount option or (2) I get completely different oom kill selection with the new mount option but not the ability to influence it. I was much happier with the direction that v7 was taking, but since v8 causes us to regress without the ability to change memcg priority, this has to be nacked.
Quoted 3 lines
- Kill the whole cgroup if
oom_groupis set and it's memory.max is reached
- Update docs and commit messages
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 4 lines · David Rientjes
Quoted 2 lines · Roman Gushchin
This patchset makes the OOM killer cgroup-aware.
Quoted 8 lines
Quoted 4 lines
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussionsNack, we specifically require
oom_priorityfor this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required.
While I understand that your usecase might require priorities I do not think this part missing is a reason to nack the cgroup based selection and kill-all parts. This can be done on top. The only important part right now is the current selection semantic - only leaf memcgs vs. size of the hierarchy). I strongly believe that comparing only leaf memcgs is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).
I didn't get to read the new version of this series yet and hope to get to it soon.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 11 lines · Michal Hocko
Quoted 10 lines
Quoted 6 lines
This patchset makes the OOM killer cgroup-aware.
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussionsNack, we specifically require
oom_priorityfor this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required.
Quoted 9 lines
While I understand that your usecase might require priorities I do not think this part missing is a reason to nack the cgroup based selection and kill-all parts. This can be done on top. The only important part right now is the current selection semantic - only leaf memcgs vs. size of the hierarchy). I strongly believe that comparing only leaf memcgs is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).
The problem is that we cannot enable the cgroup-aware oom killer and oom_group behavior because, without oom priorities, we have no ability to influence the cgroup that it chooses. It is doing two things: providing more fairness amongst cgroups by selecting based on cumulative usage rather than single large process (good!), and effectively is removing all userspace control of oom selection (bad). We want the former, but it needs to be coupled with support so that we can protect vital cgroups, regardless of their usage.
It is certainly possible to add oom priorities on top before it is merged, but I don't see why it isn't part of the patchset. We need it before its merged to avoid users playing with /proc/pid/oom_score_adj to prevent any killing in the most preferable memcg when they could have simply changed the oom priority.
Michal Hocko
maintainerQuoted 23 lines · David Rientjes
Quoted 11 lines · Michal Hocko
Quoted 10 lines
Quoted 6 lines
This patchset makes the OOM killer cgroup-aware.
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussionsNack, we specifically require
oom_priorityfor this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required.Quoted 9 lines
While I understand that your usecase might require priorities I do not think this part missing is a reason to nack the cgroup based selection and kill-all parts. This can be done on top. The only important part right now is the current selection semantic - only leaf memcgs vs. size of the hierarchy). I strongly believe that comparing only leaf memcgs is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).
Quoted 8 lines
The problem is that we cannot enable the cgroup-aware oom killer and
oom_groupbehavior because, without oom priorities, we have no ability to influence the cgroup that it chooses. It is doing two things: providing more fairness amongst cgroups by selecting based on cumulative usage rather than single large process (good!), and effectively is removing all userspace control of oom selection (bad). We want the former, but it needs to be coupled with support so that we can protect vital cgroups, regardless of their usage.
I understand that your usecase needs a more fine grained control over the selection but that alone is not a reason to nack the implementation which doesn't provide it (yet).
Quoted 2 lines
It is certainly possible to add oom priorities on top before it is merged, but I don't see why it isn't part of the patchset.
Because the semantic of the priority for non-leaf memcgs is not fully clear and I would rather have the core of the functionality merged before this is sorted out.
Quoted 4 lines
We need it before its
merged to avoid users playing with/proc/pid/oom_score_adjto prevent any killing in the most preferable memcg when they could have simply changed the oom priority.
I am sorry but I do not really understand your concern. Are you suggesting that users would start oom disable all tasks in a memcg to give it a higher priority? Even if that was the case why should such an abuse be a blocker for generic memcg aware oom killer being merged?
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 7 lines · Michal Hocko
Quoted 2 lines
It is certainly possible to add oom priorities on top before it is merged, but I don't see why it isn't part of the patchset.
Because the semantic of the priority for non-leaf memcgs is not fully clear and I would rather have the core of the functionality merged before this is sorted out.
We can't merge the core of the feature before this is sorted out because then users start to depend on behavior and we must be backwards compatible. We need a full patchset that introduces the new selection heuristic and a way for userspace to control it to either bias or prefer one cgroup over another. The kill-all mechanism is a more orthogonal feature for the cgroup-aware oom killer than oom priorities.
I have a usecase for both the cgroup-aware oom killer and its oom priorities from previous versions of this patchset, I assume that Roman does as well, and would like to see it merged bacause there are real-world usecases for it rather than hypothetical usecases that would want to do something different.
Quoted 9 lines
Quoted 4 lines
We need it before its
merged to avoid users playing with/proc/pid/oom_score_adjto prevent any killing in the most preferable memcg when they could have simply changed the oom priority.I am sorry but I do not really understand your concern. Are you suggesting that users would start oom disable all tasks in a memcg to give it a higher priority? Even if that was the case why should such an abuse be a blocker for generic memcg aware oom killer being merged?
If users do not have any way to control victim selection because of a shortcoming in the kernel implementation, they will be required to oom disable processes and let that be inherited by children they fork in the memcg hierarchy to protect cgroups that they do not want to be oom killed, regardless of their size. They simply are left with no other alternative if they want to use the cgroup-aware oom killer and/or the kill-all mechanism.
Quoted 14 lines · Michal Hocko
Quoted 4 lines · David Rientjes
Quoted 2 lines · Roman Gushchin
This patchset makes the OOM killer cgroup-aware.
Quoted 8 lines
Quoted 4 lines
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussionsNack, we specifically require
oom_priorityfor this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required.
Quoted 5 lines
While I understand that your usecase might require priorities I do not think this part missing is a reason to nack the cgroup based selection and kill-all parts. This can be done on top. The only important part right now is the current selection semantic - only leaf memcgs vs. size of the hierarchy).
I agree.
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).
One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.
Also, the opposite will make oom_semantics more weird: it will mean kill all tasks, but also treat memcg as a leaf cgroup.
Quoted 3 lines
I didn't get to read the new version of this series yet and hope to get to it soon.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.
Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
Consider that it might be not your choice (as a user) how deep is your leaf memcg. I can already see how people complain that their memcg has been killed just because it was one level deeper in the hierarchy...
I would really start simple and only allow kill-all on leaf memcgs and only compare leaf memcgs & root. If we ever need to kill whole hierarchies then allow kill-all on intermediate memcgs as well and then consider cumulative consumptions only on those that have kill-all enabled.
Or do I miss any reasonable usecase that would suffer from such a semantic?
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 13 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.
Quoted 4 lines
Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
We definitely want to support kill-all for non-leaf cgroups. A workload can consist of several cgroups and we want to clean up the whole thing on OOM. I don't see any reasons to limit this functionality to leaf cgroups only.
Hierarchies are memory consumers, we do account their usage, we do apply limits and guarantees for the hierarchies. The same is with OOM victim selection: we are reclaiming memory from the biggest consumer. Kill-all knob only defines the way _how_ we do that:
by killing one or all processes.
Just for example, we might want to take memory.low into account at some point: prefer cgroups which are above their guarantees, avoid killing those who fit. It would be hard if we're comparing cgroups from different hierarchies. The same will be with introducing oom_priorities, which is much more required functionality.
Quoted 3 lines
Consider that it might be not your choice (as a user) how deep is your leaf memcg. I can already see how people complain that their memcg has been killed just because it was one level deeper in the hierarchy...
The kill-all functionality is enforced by parent, and it seems to be following the overall memcg design. The parent cgroup enforces memory limit, memory low limit, etc.
I don't know why OOM control should be different.
Quoted 6 lines
I would really start simple and only allow kill-all on leaf memcgs and only compare leaf memcgs & root. If we ever need to kill whole hierarchies then allow kill-all on intermediate memcgs as well and then consider cumulative consumptions only on those that have kill-all enabled.
This sounds hacky to me: the whole thing is depending on cgroup v2 and is additionally explicitly opt-in.
Why do we need to introduce such incomplete functionality first, and then suffer trying to extend it and provide backward compatibility?
Also, I think we should compare root cgroup with top-level cgroups, rather than leaf cgroups. A process in the root cgroup is definitely system-level entity, and we should compare it with other top-level entities (other containerized workloads), rather then some random leaf cgroup deep inside the tree. If we decided, that we're not comparing random tasks from different cgroups, why should we do this for leaf cgroups? Is sounds like making only one step towards right direction, while we can do more.
Quoted 3 lines
Or do I miss any reasonable usecase that would suffer from such a semantic?
Kill-all for sub-trees is definitely required.
Enforcing oom_priorities for sub-trees is something that I would expect very useful too. Comparing leaf cgroups system-wide instead of processes doesn't sound good for me, we're lacking hierarchical fairness, which was one of two goals of this patchset.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 14 lines · Roman Gushchin
Quoted 13 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.
Quoted 8 lines
Quoted 4 lines
Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
We definitely want to support kill-all for non-leaf cgroups. A workload can consist of several cgroups and we want to clean up the whole thing on OOM.
Could you be more specific about such a workload? E.g. how can be such a hierarchy handled consistently when its sub-tree gets killed due to internal memory pressure? Or do you expect that none of the subtree will have hard limit configured?
Quoted 2 lines
I don't see any reasons to limit this functionality to leaf cgroups only.
Well, I wanted to start simple first and extend on top. Memcg v1 is full of seemingly interesting and very generic concepts which turned out being a headache long term.
Quoted 5 lines
Hierarchies are memory consumers, we do account their usage, we do apply limits and guarantees for the hierarchies. The same is with OOM victim selection: we are reclaiming memory from the biggest consumer. Kill-all knob only defines the way _how_ we do that:
by killing one or all processes.
But then you just enforce a structural restriction on your configuration because
root
/ \
A D
/\
B Cis a different thing than
root
/ | \
B C DAnd consider that the sole purpose of A might be a control over a non-memory resource (e.g. a cpu share distribution). Why should we discriminate B and C in such a case?
Quoted 4 lines
Just for example, we might want to take memory.low into account at some point: prefer cgroups which are above their guarantees, avoid killing those who fit. It would be hard if we're comparing cgroups from different hierarchies.
This can be reflected in the memcg oom score calculation I believe. We already do something similar during the reclaim.
Quoted 2 lines
The same will be with introducing
oom_priorities, which is much more required functionality.
More on that below.
Quoted 7 lines
Quoted 3 lines
Consider that it might be not your choice (as a user) how deep is your leaf memcg. I can already see how people complain that their memcg has been killed just because it was one level deeper in the hierarchy...
The kill-all functionality is enforced by parent, and it seems to be following the overall memcg design. The parent cgroup enforces memory limit, memory low limit, etc.
And the same is true for the memcg oom killer. It enforces the selection to the out-of-memory subtree. We are trying to be proportional on the size of the _reclaimable_ memory in that scope. Same way as with the LRU reclaim. We do not prefer larger hierarchies over smaller. We just iterate over those that have pages on LRUs (leaf memcgs with v2) and scan/reclaim proportionally to their size. Why should the oom killer decision be any different in that regards?
Quoted 1 line
I don't know why OOM control should be different.
I am not arguing that kill-all functionality on non-leaf is wrong. I just haven't heard the usecase for it yet. I am also not opposed to consider the cumulative size of non-leaf memcg if it is kill-all as the cumulative size will be reclaimed then. But I fail to see why we should prefer larger hierarchies when the resulting memcg victim is much smaller in the end.
Quoted 11 lines
Quoted 5 lines
I would really start simple and only allow kill-all on leaf memcgs and only compare leaf memcgs & root. If we ever need to kill whole hierarchies then allow kill-all on intermediate memcgs as well and then consider cumulative consumptions only on those that have kill-all enabled.
This sounds hacky to me: the whole thing is depending on cgroup v2 and is additionally explicitly opt-in.
Why do we need to introduce such incomplete functionality first, and then suffer trying to extend it and provide backward compatibility?
Why would a backward compatibility be a problem? kill-all on non-leaf memcgs should be seamless. We would simply allow setting the knob. Adding a priority shouldn't be a problem either. A new knob would be added. Any memcg with a non-zero priority would be considered during selection for example (cumulative size would be considered as a tie-breaker for non-leaf memcgs and a victim selected from the largest hierarchy/leaf memcg - but that really needs to be thought through and hear about specific usecases).
Quoted 8 lines
Also, I think we should compare root cgroup with top-level cgroups, rather than leaf cgroups. A process in the root cgroup is definitely system-level entity, and we should compare it with other top-level entities (other containerized workloads), rather then some random leaf cgroup deep inside the tree. If we decided, that we're not comparing random tasks from different cgroups, why should we do this for leaf cgroups? Is sounds like making only one step towards right direction, while we can do more.
The main problem I have with that is mentioned above. A single hierarchy enforces some structural constrains when multiple controllers are in place.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 20 lines · Michal Hocko
Quoted 19 lines · Roman Gushchin
Quoted 17 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
Quoted 7 lines
Quoted 3 lines
We definitely want to support kill-all for non-leaf cgroups. A workload can consist of several cgroups and we want to clean up the whole thing on OOM.
Could you be more specific about such a workload? E.g. how can be such a hierarchy handled consistently when its sub-tree gets killed due to internal memory pressure?
Or just system-wide OOM.
Quoted 2 lines
Or do you expect that none of the subtree will
have hard limit configured?
And this can also be a case: the whole workload may have hard limit configured, while internal memcgs have only memory.low set for "soft" prioritization.
Quoted 9 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B C
Quoted 5 lines
is a different thing than
root / | \ B C D
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with oom_priorities (select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 14 lines · Roman Gushchin
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C D
Quoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.
Yes, oom_priority cannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 25 lines · David Rientjes
Quoted 14 lines · Roman Gushchin
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.
Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
I believe, it's a solvable problem: we can require CAP_SYS_RESOURCE to set the oom_priority below parent's value, or something like this.
But it looks more complex, and I'm not sure there are real examples, when we have to compare memcgs, which are on different levels (or in different subtrees).
In any case, oom_priorities and size-based comparison should share the same tree-walking policy. And I still would prefer comparing sizes and priorities independently on each level.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 33 lines · Roman Gushchin
Quoted 25 lines · David Rientjes
Quoted 14 lines · Roman Gushchin
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
Quoted 2 lines
I believe, it's a solvable problem: we can require
CAP_SYS_RESOURCEto set theoom_prioritybelow parent's value, or something like this.
As said in other email. We can make priorities hierarchical (in the same sense as hard limit or others) so that children cannot override their parent.
Quoted 3 lines
But it looks more complex, and I'm not sure there are real examples, when we have to compare memcgs, which are on different levels (or in different subtrees).
Well, I have given you one that doesn't sounds completely insane to me in other email. You may need an intermediate level for other than memcg controller. The whole concept of significance of the hierarchy level seems really odd to me. Or am I wrong here?
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 34 lines · Michal Hocko
Quoted 33 lines · Roman Gushchin
Quoted 31 lines · David Rientjes
Quoted 14 lines · Roman Gushchin
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
Quoted 6 lines
Quoted 2 lines
I believe, it's a solvable problem: we can require
CAP_SYS_RESOURCEto set theoom_prioritybelow parent's value, or something like this.As said in other email. We can make priorities hierarchical (in the same sense as hard limit or others) so that children cannot override their parent.
You mean they can set the knob to any value, but parent's value is enforced, if it's greater than child's value?
If so, this sounds logical to me. Then we have size-based comparison and priority-based comparison with similar rules, and all use cases are covered.
Ok, can we stick with this design?
Then I'll return oom_priorities in place, and post a (hopefully) final version.
Thanks!
David Rientjes
reviewerQuoted 4 lines · Roman Gushchin
Quoted 3 lines
As said in other email. We can make priorities hierarchical (in the same sense as hard limit or others) so that children cannot override their parent.
Quoted 9 lines
You mean they can set the knob to any value, but parent's value is enforced, if it's greater than child's value?
If so, this sounds logical to me. Then we have size-based comparison and priority-based comparison with similar rules, and all use cases are covered.
Ok, can we stick with this design?
Then I'll returnoom_prioritiesin place, and post a (hopefully) final version.
I just want to make sure that we are going with your original implementation here: that oom_priority is only effective for compare sibling memory cgroups and nothing beyond that. The value alone has no relationship to any ancestor. We can't set oom_priority based on the priorities of any other memory cgroups other than our own siblings because we have no control over how those change.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 30 lines · Roman Gushchin
Quoted 23 lines
Quoted 14 lines
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
Quoted 7 lines
I believe, it's a solvable problem: we can require
CAP_SYS_RESOURCEto set theoom_prioritybelow parent's value, or something like this.But it looks more complex, and I'm not sure there are real examples, when we have to compare memcgs, which are on different levels (or in different subtrees).
It's actually much more complex because in our environment we'd need an "activity manager" with CAP_SYS_RESOURCE to control oom priorities of user subcontainers when today it need only be concerned with top-level memory cgroups. Users can create their own hierarchies with their own oom priorities at will, it doesn't alter the selection heuristic for another other user running on the same system and gives them full control over the selection in their own subtree. We shouldn't need to have a system-wide daemon with CAP_SYS_RESOURCE be required to manage subcontainers when nothing else requires it. I believe it's also much easier to document:oom_priority is considered for all sibling cgroups at each level of the hierarchy and the cgroup with the lowest priority value gets iterated.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 40 lines · David Rientjes
Quoted 30 lines · Roman Gushchin
Quoted 23 lines
Quoted 14 lines
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.Quoted 7 lines
I believe, it's a solvable problem: we can require
CAP_SYS_RESOURCEto set theoom_prioritybelow parent's value, or something like this.But it looks more complex, and I'm not sure there are real examples, when we have to compare memcgs, which are on different levels (or in different subtrees).
Quoted 11 lines
It's actually much more complex because in our environment we'd need an "activity manager" with
CAP_SYS_RESOURCEto control oom priorities of user subcontainers when today it need only be concerned with top-level memory cgroups. Users can create their own hierarchies with their own oom priorities at will, it doesn't alter the selection heuristic for another other user running on the same system and gives them full control over the selection in their own subtree. We shouldn't need to have a system-wide daemon withCAP_SYS_RESOURCEbe required to manage subcontainers when nothing else requires it. I believe it's also much easier to document:oom_priorityis considered for all sibling cgroups at each level of the hierarchy and the cgroup with the lowest priority value gets iterated.
I do agree actually. System-wide OOM priorities make no sense.
Always compare sibling cgroups, either by priority or size, seems to be simple, clear and powerful enough for all reasonable use cases. Am I right, that it's exactly what you've used internally? This is a perfect confirmation, I believe.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 12 lines · Roman Gushchin
Quoted 11 lines
It's actually much more complex because in our environment we'd need an "activity manager" with
CAP_SYS_RESOURCEto control oom priorities of user subcontainers when today it need only be concerned with top-level memory cgroups. Users can create their own hierarchies with their own oom priorities at will, it doesn't alter the selection heuristic for another other user running on the same system and gives them full control over the selection in their own subtree. We shouldn't need to have a system-wide daemon withCAP_SYS_RESOURCEbe required to manage subcontainers when nothing else requires it. I believe it's also much easier to document:oom_priorityis considered for all sibling cgroups at each level of the hierarchy and the cgroup with the lowest priority value gets iterated.
Quoted 7 lines
I do agree actually. System-wide OOM priorities make no sense.
Always compare sibling cgroups, either by priority or size, seems to be simple, clear and powerful enough for all reasonable use cases. Am I right, that it's exactly what you've used internally? This is a perfect confirmation, I believe.
We've used it for at least four years, I added my Tested-by to your patch, we would convert to your implementation if it is merged upstream, and I would enthusiastically support your patch if you would integrate it back into your series.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 25 lines · David Rientjes
Quoted 14 lines · Roman Gushchin
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.
Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
Could you be more speicific about your usecase? What would be a problem If we allow to only increase priority in children (like other hierarchical controls).
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 30 lines · Michal Hocko
Quoted 23 lines
Quoted 14 lines
Quoted 8 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C DQuoted 8 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
The only real concern I have is that then we have to do the same with
oom_priorities(select largest priority tree-wide), and this will limit an ability to enforce the priority by parent cgroup.Quoted 6 lines
Yes,
oom_prioritycannot select the largest priority tree-wide for exactly that reason. We need the ability to control from which subtree the kill occurs in ancestor cgroups. If multiple jobs are allocated their own cgroups and they can own memory.oom_priority for their own subcontainers, this becomes quite powerful so they can define their own oom priorities. Otherwise, they can easily override the oom priorities of other cgroups.
Quoted 4 lines
Could you be more speicific about your usecase? What would be a problem If we allow to only increase priority in children (like other hierarchical controls).
For memcg constrained oom conditions, there is only a theoretical issue if the subtree is not under the control of a single user and various users can alter their priorities without knowledge of the priorities of other children in the same subtree that is oom, or those values change without knowledge of a child. I don't know of anybody that configures memory cgroup hierarchies that way, though.
The problem is more obvious in system oom conditions. If we have two top-level memory cgroups with the same "job" priority, they get the same oom priority. The user who configures subcontainers is now always targeted for oom kill in an "increase priority in children" policy.
The hierarchy becomes this:
root
/ \
A D
/ \ / | \
B C E F Gwhere A/memory.oom_priority == D/memory.oom_priority.
D wants to kill in order of E -> F -> G, but can't configure that if B = A - 1 and C = B - 1. It also shouldn't need to adjust its own oom priorities based on a hierarchy outside its control and which can change at any time at the discretion of the user (with namespaces you may not even be able to access it).
But also if A/memory.oom_priority = D/memory.oom_priority - 100, A is preferred unless its subcontainers configure themselves in a way where they have higher oom priority values than E, F, and G. That may yield very different results when additional jobs get scheduled on the system (and H tree) where the user has full control over their own oom priorities, even when the value must only increase.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 53 lines · Roman Gushchin
Quoted 20 lines · Michal Hocko
Quoted 19 lines · Roman Gushchin
Quoted 17 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
Quoted 7 lines
Quoted 3 lines
We definitely want to support kill-all for non-leaf cgroups. A workload can consist of several cgroups and we want to clean up the whole thing on OOM.
Could you be more specific about such a workload? E.g. how can be such a hierarchy handled consistently when its sub-tree gets killed due to internal memory pressure?
Or just system-wide OOM.
Quoted 2 lines
Or do you expect that none of the subtree will
have hard limit configured?And this can also be a case: the whole workload may have hard limit configured, while internal memcgs have only memory.low set for "soft" prioritization.
Quoted 9 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B CQuoted 5 lines
is a different thing than
root / | \ B C D
Quoted 3 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
Well, I am worried that the difference will come unexpected when a deeper hierarchy is needed because of the structural needs.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 54 lines · Michal Hocko
Quoted 53 lines · Roman Gushchin
Quoted 20 lines · Michal Hocko
Quoted 19 lines · Roman Gushchin
Quoted 17 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Wed, Sep 13, 2017 at 02:29:14PM +0200, Michal Hocko wrote:
[...]
Quoted 9 lines
Quoted 4 lines
I strongly believe that comparing only leaf memcgs
is more straightforward and it doesn't lead to unexpected results as mentioned before (kill a small memcg which is a part of the larger sub-hierarchy).One of two main goals of this patchset is to introduce cgroup-level
fairness: bigger cgroups should be affected more than smaller, despite the size of tasks inside. I believe the same principle should be used for cgroups.Yes bigger cgroups should be preferred but I fail to see why bigger hierarchies should be considered as well if they are not kill-all. And whether non-leaf memcgs should allow kill-all is not entirely clear to me. What would be the usecase?
Quoted 7 lines
Quoted 3 lines
We definitely want to support kill-all for non-leaf cgroups. A workload can consist of several cgroups and we want to clean up the whole thing on OOM.
Could you be more specific about such a workload? E.g. how can be such a hierarchy handled consistently when its sub-tree gets killed due to internal memory pressure?
Or just system-wide OOM.
Quoted 2 lines
Or do you expect that none of the subtree will
have hard limit configured?And this can also be a case: the whole workload may have hard limit configured, while internal memcgs have only memory.low set for "soft" prioritization.
Quoted 14 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B Cis a different thing than
root / | \ B C D
Quoted 3 lines
Quoted 3 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
I've tried to implement this approach, and it's really arguable. Although your example looks reasonable, the opposite example is also valid:
you might want to compare whole hierarchies, and it's a quite typical usecase.
Assume, you have several containerized workloads on a machine (probably, each will be contained in a memcg with memory.max set), with some hierarchy of cgroups inside. Then in case of global memory shortage we want to reclaim some memory from the biggest workload, and the selection should not depend on group_oom settings. It would be really strange, if setting group_oom will higher the chances to be killed.
In other words, let's imagine processes as leaf nodes in memcg tree. We decided to select the biggest memcg and kill one or more processes inside (depending on group_oom setting), but the memcg selection doesn't depend on it. We do not compare processes from different cgroups, as well as cgroups with processes. The same should apply to cgroups: why do we want to compare cgroups from different sub-trees?
While size-based comparison can be implemented with this approach, the priority-based is really weird (as David mentioned).
If priorities have no hierarchical meaning at all, we lack the very important ability to enforce hierarchy oom_priority. Otherwise we have to invent some complex rules of oom_priority propagation (e.g. is someone is raising the oom_priority in parent, should it be applied to children immediately, etc).
The oom_group knob meaning also becoms more complex. It affects both the victim selection and OOM action. _ANY_ mechanism which allows to affect OOM victim selection (either priorities, either bpf-based approach) should not have global system-wide meaning, it breaks everything.
I do understand your point, but the same is true for other stuff, right? E.g. cpu time distribution (and io, etc) depends on hierarchy configuration. It's a limitation, but it's ok, as user should create a hierarchy which reflects some logical relations between processes and groups of processes. Otherwise we're going to the configuration hell.
In any case, OOM is a last resort mechanism. The goal is to reclaim some memory and do not crash the system or do not leave it in totally broken state. Any really complex mm in userspace should be applied _before_ OOM happens. So, I don't think we have to support all possible configurations here, if we're able to achieve the main goal (kill some processes and do not leave broken systems/containers).
Michal Hocko
maintainerI would really appreciate some feedback from Tejun, Johannes here.
Quoted 3 lines · Roman Gushchin
Quoted 2 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Fri, Sep 15, 2017 at 12:58:26PM +0200, Michal Hocko wrote:
[...]
Quoted 36 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B Cis a different thing than
root / | \ B C DQuoted 3 lines
Quoted 3 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
I've tried to implement this approach, and it's really arguable. Although your example looks reasonable, the opposite example is also valid:
you might want to compare whole hierarchies, and it's a quite typical usecase.Assume, you have several containerized workloads on a machine (probably, each will be contained in a memcg with memory.max set), with some hierarchy of cgroups inside. Then in case of global memory shortage we want to reclaim some memory from the biggest workload, and the selection should not depend on
group_oomsettings. It would be really strange, if settinggroup_oomwill higher the chances to be killed.In other words, let's imagine processes as leaf nodes in memcg tree. We decided to select the biggest memcg and kill one or more processes inside (depending on
group_oomsetting), but the memcg selection doesn't depend on it. We do not compare processes from different cgroups, as well as cgroups with processes. The same should apply to cgroups: why do we want to compare cgroups from different sub-trees?
Quoted 6 lines
While size-based comparison can be implemented with this approach, the priority-based is really weird (as David mentioned).
If priorities have no hierarchical meaning at all, we lack the very important ability to enforce hierarchyoom_priority. Otherwise we have to invent some complex rules ofoom_prioritypropagation (e.g. is someone is raising theoom_priorityin parent, should it be applied to children immediately, etc).
I would really forget about the priority at this stage. This needs really much more thinking and I consider the David's usecase very specialized to use it as a template for a general purpose oom prioritization. I might be wrong here of course...
Quoted 10 lines
The
oom_groupknob meaning also becoms more complex. It affects both the victim selection and OOM action. _ANY_ mechanism which allows to affect OOM victim selection (either priorities, either bpf-based approach) should not have global system-wide meaning, it breaks everything.I do understand your point, but the same is true for other stuff, right? E.g. cpu time distribution (and io, etc) depends on hierarchy configuration. It's a limitation, but it's ok, as user should create a hierarchy which reflects some logical relations between processes and groups of processes. Otherwise we're going to the configuration hell.
And that is _exactly_ my concern. We surely do not want tell people that they have to consider their cgroup tree structure to control the global oom behavior. You simply do not have that constrain with leaf-only semantic and if kill-all intermediate nodes are used then there is an explicit opt-in for the hierarchy considerations.
Quoted 6 lines
In any case, OOM is a last resort mechanism. The goal is to reclaim some memory and do not crash the system or do not leave it in totally broken state. Any really complex mm in userspace should be applied _before_ OOM happens. So, I don't think we have to support all possible configurations here, if we're able to achieve the main goal (kill some processes and do not leave broken systems/containers).
True but we want to have the semantic reasonably understandable. And it is quite hard to explain that the oom killer hasn't selected the largest memcg just because it happened to be in a deeper hierarchy which has been configured to cover a different resource.
I am sorry to repeat my self and I will not argue if there is a prevalent agreement that level-by-level comparison is considered desirable and documented behavior but, by all means, do not define this semantic based on a priority requirements and/or implementation details.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Johannes Weiner
maintainerQuoted 50 lines · Michal Hocko
I would really appreciate some feedback from Tejun, Johannes here.
Quoted 3 lines · Roman Gushchin
Quoted 2 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Fri, Sep 15, 2017 at 12:58:26PM +0200, Michal Hocko wrote:
[...]
Quoted 36 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B Cis a different thing than
root / | \ B C DQuoted 3 lines
Quoted 3 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
I've tried to implement this approach, and it's really arguable. Although your example looks reasonable, the opposite example is also valid:
you might want to compare whole hierarchies, and it's a quite typical usecase.Assume, you have several containerized workloads on a machine (probably, each will be contained in a memcg with memory.max set), with some hierarchy of cgroups inside. Then in case of global memory shortage we want to reclaim some memory from the biggest workload, and the selection should not depend on
group_oomsettings. It would be really strange, if settinggroup_oomwill higher the chances to be killed.In other words, let's imagine processes as leaf nodes in memcg tree. We decided to select the biggest memcg and kill one or more processes inside (depending on
group_oomsetting), but the memcg selection doesn't depend on it. We do not compare processes from different cgroups, as well as cgroups with processes. The same should apply to cgroups: why do we want to compare cgroups from different sub-trees?Quoted 6 lines
While size-based comparison can be implemented with this approach, the priority-based is really weird (as David mentioned).
If priorities have no hierarchical meaning at all, we lack the very important ability to enforce hierarchyoom_priority. Otherwise we have to invent some complex rules ofoom_prioritypropagation (e.g. is someone is raising theoom_priorityin parent, should it be applied to children immediately, etc).
Quoted 4 lines
I would really forget about the priority at this stage. This needs really much more thinking and I consider the David's usecase very specialized to use it as a template for a general purpose oom prioritization. I might be wrong here of course...
No, I agree.
Quoted 11 lines
Quoted 6 lines
In any case, OOM is a last resort mechanism. The goal is to reclaim some memory and do not crash the system or do not leave it in totally broken state. Any really complex mm in userspace should be applied _before_ OOM happens. So, I don't think we have to support all possible configurations here, if we're able to achieve the main goal (kill some processes and do not leave broken systems/containers).
True but we want to have the semantic reasonably understandable. And it is quite hard to explain that the oom killer hasn't selected the largest memcg just because it happened to be in a deeper hierarchy which has been configured to cover a different resource.
Going back to Michal's example, say the user configured the following:
root
/ \
A D
/ \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroups
What the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
Let's consider an extreme case of this conundrum:
root
/ \
A B
/|\ |A1-A1000 B1
Again we find:
- A > B
- A1 to A1000 and B1 are oomgroups
But:
- A1 to A1000 individually are tiny, B1 is huge
Going level by level, we'd pick A as the bigger hierarchy in the system, and then kill off one of the tiny groups A1 to A1000.
Conversely, going for biggest consumer regardless of hierarchy, we'd compare A1 to A1000 and B1, then pick B1 as the biggest single atomic memory consumer in the system and kill all its tasks.
Which one of these two fits both the purpose and our historic approach to OOM killing better?
As was noted in this thread, OOM is the last resort to avoid a memory deadlock. Killing the biggest consumer is most likely to resolve this precarious situation. It is also most likely to catch buggy software with memory leaks or runaway allocations, which is a nice bonus.
Killing a potentially tiny consumer inside the biggest top-level hierarchy doesn't achieve this. I think we can all agree on this.
But also, global OOM in particular means that the hierarchical approach to allocating the system's memory among cgroups has failed. The user expressed control over memory in a way that wasn't sufficient to isolate memory consumption between the different hierarchies. IMO what follows from that is that the hierarchy itself is a questionable guide to finding a culprit.
So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them.
Quoted 133 lines · Johannes Weiner
Quoted 50 lines · Michal Hocko
I would really appreciate some feedback from Tejun, Johannes here.
Quoted 3 lines · Roman Gushchin
Quoted 2 lines · Michal Hocko
Quoted 1 line · Roman Gushchin
On Fri, Sep 15, 2017 at 12:58:26PM +0200, Michal Hocko wrote:
[...]
Quoted 36 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
But then you just enforce a structural restriction on your configuration because
root / \ A D /\ B Cis a different thing than
root / | \ B C DQuoted 3 lines
Quoted 3 lines
I actually don't have a strong argument against an approach to select largest leaf or kill-all-set memcg. I think, in practice there will be no much difference.
I've tried to implement this approach, and it's really arguable. Although your example looks reasonable, the opposite example is also valid:
you might want to compare whole hierarchies, and it's a quite typical usecase.Assume, you have several containerized workloads on a machine (probably, each will be contained in a memcg with memory.max set), with some hierarchy of cgroups inside. Then in case of global memory shortage we want to reclaim some memory from the biggest workload, and the selection should not depend on
group_oomsettings. It would be really strange, if settinggroup_oomwill higher the chances to be killed.In other words, let's imagine processes as leaf nodes in memcg tree. We decided to select the biggest memcg and kill one or more processes inside (depending on
group_oomsetting), but the memcg selection doesn't depend on it. We do not compare processes from different cgroups, as well as cgroups with processes. The same should apply to cgroups: why do we want to compare cgroups from different sub-trees?Quoted 6 lines
While size-based comparison can be implemented with this approach, the priority-based is really weird (as David mentioned).
If priorities have no hierarchical meaning at all, we lack the very important ability to enforce hierarchyoom_priority. Otherwise we have to invent some complex rules ofoom_prioritypropagation (e.g. is someone is raising theoom_priorityin parent, should it be applied to children immediately, etc).Quoted 4 lines
I would really forget about the priority at this stage. This needs really much more thinking and I consider the David's usecase very specialized to use it as a template for a general purpose oom prioritization. I might be wrong here of course...
No, I agree.
Quoted 11 lines
Quoted 6 lines
In any case, OOM is a last resort mechanism. The goal is to reclaim some memory and do not crash the system or do not leave it in totally broken state. Any really complex mm in userspace should be applied _before_ OOM happens. So, I don't think we have to support all possible configurations here, if we're able to achieve the main goal (kill some processes and do not leave broken systems/containers).
True but we want to have the semantic reasonably understandable. And it is quite hard to explain that the oom killer hasn't selected the largest memcg just because it happened to be in a deeper hierarchy which has been configured to cover a different resource.
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
Let's consider an extreme case of this conundrum:
root / \ A B /|\ |A1-A1000 B1
Again we find:
- A > B
- A1 to A1000 and B1 are oomgroups
But:
- A1 to A1000 individually are tiny, B1 is hugeGoing level by level, we'd pick A as the bigger hierarchy in the system, and then kill off one of the tiny groups A1 to A1000.
Conversely, going for biggest consumer regardless of hierarchy, we'd compare A1 to A1000 and B1, then pick B1 as the biggest single atomic memory consumer in the system and kill all its tasks.
Which one of these two fits both the purpose and our historic approach to OOM killing better?
As was noted in this thread, OOM is the last resort to avoid a memory deadlock. Killing the biggest consumer is most likely to resolve this precarious situation. It is also most likely to catch buggy software with memory leaks or runaway allocations, which is a nice bonus.
Killing a potentially tiny consumer inside the biggest top-level hierarchy doesn't achieve this. I think we can all agree on this.
But also, global OOM in particular means that the hierarchical approach to allocating the system's memory among cgroups has failed. The user expressed control over memory in a way that wasn't sufficient to isolate memory consumption between the different hierarchies. IMO what follows from that is that the hierarchy itself is a questionable guide to finding a culprit.
Quoted 3 lines
So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them.
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
The only thing, I'm slightly concerned, that due to the way how we calculate the memory footprint for tasks and memory cgroups, we will have a number of weird edge cases. For instance, when putting a single process into the group_oom memcg will alter the oom_score significantly and result in significantly different chances to be killed. An obvious example will be a task with oom_score_adj set to any non-extreme (other than 0 and -1000) value, but it can also happen in case of constrained alloc, for instance.
If it considered to be a minor issue, we can choose this approach.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerOn Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]
Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
Quoted 7 lines
The only thing, I'm slightly concerned, that due to the way how we calculate the memory footprint for tasks and memory cgroups, we will have a number of weird edge cases. For instance, when putting a single process into the
group_oommemcg will alter theoom_scoresignificantly and result in significantly different chances to be killed. An obvious example will be a task withoom_score_adjset to any non-extreme (other than 0 and -1000) value, but it can also happen in case of constrained alloc, for instance.
I am not sure I understand. Are you talking about root memcg comparing to other memcgs?
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
As I understand Johannes, he suggested to compare individual processes with group_oom mem cgroups. In other words, always select a killable entity with the biggest memory footprint.
This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on group_oom setting, so by default I'm selecting the biggest task in the biggest memcg.
While the approach suggested by Johannes looks clear and reasonable, I'm slightly concerned about possible implementation issues, which I've described below:
Quoted 11 lines
Quoted 8 lines
The only thing, I'm slightly concerned, that due to the way how we calculate the memory footprint for tasks and memory cgroups, we will have a number of weird edge cases. For instance, when putting a single process into the
group_oommemcg will alter theoom_scoresignificantly and result in significantly different chances to be killed. An obvious example will be a task withoom_score_adjset to any non-extreme (other than 0 and -1000) value, but it can also happen in case of constrained alloc, for instance.I am not sure I understand. Are you talking about root memcg comparing to other memcgs?
Not only, but root memcg in this case will be another complication. We can also use the same trick for all memcg (define memcg oom_score as maximum oom_score of the belonging tasks), it will turn group_oom into pure container cleanup solution, without changing victim selection algorithm
But, again, I'm not against approach suggested by Johannes. I think that overall it's the best possible semantics, if we're not taking some implementation details into account.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 13 lines · Roman Gushchin
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
Quoted 7 lines
As I understand Johannes, he suggested to compare individual processes with
group_oommem cgroups. In other words, always select a killable entity with the biggest memory footprint.This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on
group_oomsetting, so by default I'm selecting the biggest task in the biggest memcg.
My reading is that he is actually proposing the same thing I've been mentioning. Simply select the biggest killable entity (leaf memcg or group_oom hierarchy) and either kill the largest task in that entity (for !group_oom) or the whole memcg/hierarchy otherwise.
Quoted 13 lines
While the approach suggested by Johannes looks clear and reasonable, I'm slightly concerned about possible implementation issues, which I've described below:
Quoted 9 lines
Quoted 8 lines
The only thing, I'm slightly concerned, that due to the way how we calculate the memory footprint for tasks and memory cgroups, we will have a number of weird edge cases. For instance, when putting a single process into the
group_oommemcg will alter theoom_scoresignificantly and result in significantly different chances to be killed. An obvious example will be a task withoom_score_adjset to any non-extreme (other than 0 and -1000) value, but it can also happen in case of constrained alloc, for instance.
Quoted 7 lines
Quoted 2 lines
I am not sure I understand. Are you talking about root memcg comparing to other memcgs?
Not only, but root memcg in this case will be another complication. We can also use the same trick for all memcg (define memcg
oom_scoreas maximumoom_scoreof the belonging tasks), it will turngroup_oominto pure container cleanup solution, without changing victim selection algorithm
I fail to see the problem to be honest. Simply evaluate the memcg_score you have so far with one minor detail. You only check memcgs which have tasks (rather than check for leaf node check) or it is group_oom. An intermediate memcg will get a cumulative size of the whole subhierarchy and then you know you can skip the subtree because any subtree can be larger.
Quoted 3 lines
But, again, I'm not against approach suggested by Johannes. I think that overall it's the best possible semantics, if we're not taking some implementation details into account.
I do not see those implementation details issues and let me repeat do not develop a semantic based on implementation details.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 18 lines · Michal Hocko
Quoted 17 lines · Roman Gushchin
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
As I understand Johannes, he suggested to compare individual processes with
group_oommem cgroups. In other words, always select a killable entity with the biggest memory footprint.
Quoted 8 lines
Quoted 3 lines
This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on
group_oomsetting, so by default I'm selecting the biggest task in the biggest memcg.My reading is that he is actually proposing the same thing I've been mentioning. Simply select the biggest killable entity (leaf memcg or
group_oomhierarchy) and either kill the largest task in that entity (for !group_oom) or the whole memcg/hierarchy otherwise.
He wrote the following:
"So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them."
Quoted 28 lines
Quoted 14 lines
While the approach suggested by Johannes looks clear and reasonable, I'm slightly concerned about possible implementation issues, which I've described below:
Quoted 9 lines
Quoted 8 lines
The only thing, I'm slightly concerned, that due to the way how we calculate the memory footprint for tasks and memory cgroups, we will have a number of weird edge cases. For instance, when putting a single process into the
group_oommemcg will alter theoom_scoresignificantly and result in significantly different chances to be killed. An obvious example will be a task withoom_score_adjset to any non-extreme (other than 0 and -1000) value, but it can also happen in case of constrained alloc, for instance.Quoted 7 lines
Quoted 2 lines
I am not sure I understand. Are you talking about root memcg comparing to other memcgs?
Not only, but root memcg in this case will be another complication. We can also use the same trick for all memcg (define memcg
oom_scoreas maximumoom_scoreof the belonging tasks), it will turngroup_oominto pure container cleanup solution, without changing victim selection algorithmI fail to see the problem to be honest. Simply evaluate the
memcg_scoreyou have so far with one minor detail. You only check memcgs which have tasks (rather than check for leaf node check) or it isgroup_oom. An intermediate memcg will get a cumulative size of the whole subhierarchy and then you know you can skip the subtree because any subtree can be larger.
Quoted 6 lines
Quoted 3 lines
But, again, I'm not against approach suggested by Johannes. I think that overall it's the best possible semantics, if we're not taking some implementation details into account.
I do not see those implementation details issues and let me repeat do not develop a semantic based on implementation details.
There are no problems in "select the biggest leaf or group_oom memcg, then kill the biggest task or all tasks depending on group_oom" approach, which you're describing. Comparing tasks and memcgs (what Johannes is suggesting) may have some issues.
Thanks!
Michal Hocko
maintainerQuoted 28 lines · Roman Gushchin
Quoted 18 lines · Michal Hocko
Quoted 17 lines · Roman Gushchin
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
As I understand Johannes, he suggested to compare individual processes with
group_oommem cgroups. In other words, always select a killable entity with the biggest memory footprint.Quoted 8 lines
Quoted 3 lines
This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on
group_oomsetting, so by default I'm selecting the biggest task in the biggest memcg.My reading is that he is actually proposing the same thing I've been mentioning. Simply select the biggest killable entity (leaf memcg or
group_oomhierarchy) and either kill the largest task in that entity (for !group_oom) or the whole memcg/hierarchy otherwise.
Quoted 4 lines
He wrote the following:
"So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them."
I will let Johannes to comment but I believe this is just a misunderstanding. If we compared only the biggest task from each memcg then we are basically losing our fairness objective, aren't we?
Signature · 2 lines
Michal Hocko SUSE Labs
Johannes Weiner
maintainerQuoted 29 lines · Michal Hocko
Quoted 28 lines · Roman Gushchin
Quoted 26 lines · Michal Hocko
Quoted 13 lines · Roman Gushchin
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
Quoted 7 lines
As I understand Johannes, he suggested to compare individual processes with
group_oommem cgroups. In other words, always select a killable entity with the biggest memory footprint.This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on
group_oomsetting, so by default I'm selecting the biggest task in the biggest memcg.My reading is that he is actually proposing the same thing I've been mentioning. Simply select the biggest killable entity (leaf memcg or
group_oomhierarchy) and either kill the largest task in that entity (for !group_oom) or the whole memcg/hierarchy otherwise.
Quoted 8 lines
Quoted 4 lines
He wrote the following:
"So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them."I will let Johannes to comment but I believe this is just a misunderstanding. If we compared only the biggest task from each memcg then we are basically losing our fairness objective, aren't we?
Sorry about the confusion.
Yeah I was making the case for what Michal proposed, to kill the biggest terminal consumer, which is either a task or an oomgroup.
You'd basically iterate through all the tasks and cgroups in the system and pick the biggest task that isn't in an oom group or the biggest oom group and then kill that.
Yeah, you'd have to compare the memory footprints of tasks with the memory footprints of cgroups. These aren't defined identically, and tasks don't get attributed every type of allocation that a cgroup would. But it should get us in the ballpark, and I cannot picture a scenario where this would lead to a completely undesirable outcome.
I'm excited to see this being discussed again - it's been years since the last attempt. I've tried to stay out of the conversation, but I feel obligated say something and then go back to lurking.
Quoted 48 lines · Johannes Weiner
Quoted 29 lines · Michal Hocko
Quoted 28 lines · Roman Gushchin
Quoted 26 lines · Michal Hocko
Quoted 13 lines · Roman Gushchin
Quoted 11 lines · Michal Hocko
On Mon 25-09-17 19:15:33, Roman Gushchin wrote:
[...]Quoted 5 lines
I'm not against this model, as I've said before. It feels logical, and will work fine in most cases.
In this case we can drop any mount/boot options, because it preserves the existing behavior in the default configuration. A big advantage.
I am not sure about this. We still need an opt-in, ragardless, because selecting the largest process from the largest memcg != selecting the largest task (just consider memcgs with many processes example).
Quoted 7 lines
As I understand Johannes, he suggested to compare individual processes with
group_oommem cgroups. In other words, always select a killable entity with the biggest memory footprint.This is slightly different from my v8 approach, where I treat leaf memcgs as indivisible memory consumers independent on
group_oomsetting, so by default I'm selecting the biggest task in the biggest memcg.My reading is that he is actually proposing the same thing I've been mentioning. Simply select the biggest killable entity (leaf memcg or
group_oomhierarchy) and either kill the largest task in that entity (for !group_oom) or the whole memcg/hierarchy otherwise.Quoted 8 lines
Quoted 4 lines
He wrote the following:
"So I'm leaning toward the second model: compare all oomgroups and standalone tasks in the system with each other, independent of the failed hierarchical control structure. Then kill the biggest of them."I will let Johannes to comment but I believe this is just a misunderstanding. If we compared only the biggest task from each memcg then we are basically losing our fairness objective, aren't we?
Sorry about the confusion.
Yeah I was making the case for what Michal proposed, to kill the biggest terminal consumer, which is either a task or an oomgroup.
You'd basically iterate through all the tasks and cgroups in the system and pick the biggest task that isn't in an oom group or the biggest oom group and then kill that.
Quoted 5 lines
Yeah, you'd have to compare the memory footprints of tasks with the memory footprints of cgroups. These aren't defined identically, and tasks don't get attributed every type of allocation that a cgroup would. But it should get us in the ballpark, and I cannot picture a scenario where this would lead to a completely undesirable outcome.
That last sentence:
Quoted 1 line
I cannot picture a scenario where this would lead to a completely undesirable outcome.
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG. We need OOM behavior to kill in a deterministic order configured by policy. Sometimes, I would literally prefer to kill every other cgroup before killing "the big one". The policy is *all* that matters for shared clusters of varying users and priorities.
We did this in Borg, and it works REALLY well. Has for years. Now that the world is adopting Kubernetes we need it again, only it's much harder to carry a kernel patch in this case.
Michal Hocko
maintainerOn Tue 26-09-17 20:37:37, Tim Hockin wrote:
[...]
Quoted 3 lines
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG.
I do not think we have discussed anything resembling the current approach. And I would really appreciate some more examples where decisions based on leaf nodes would be EXACTLY WRONG.
Quoted 2 lines
We need OOM behavior to kill in a deterministic order configured by policy.
And nobody is objecting to this usecase. I think we can build a priority policy on top of leaf-based decision as well. The main point we are trying to sort out here is a reasonable semantic that would work for most workloads. Sibling based selection will simply not work on those that have to use deeper hierarchies for organizational purposes. I haven't heard a counter argument for that example yet.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 10 lines · Michal Hocko
On Tue 26-09-17 20:37:37, Tim Hockin wrote:
[...]Quoted 3 lines
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG.
I do not think we have discussed anything resembling the current approach. And I would really appreciate some more examples where decisions based on leaf nodes would be EXACTLY WRONG.
I would agree here.
The discussing two-step approach (select biggest leaf or oom_group memcg, then select largest process inside) does really look as a way to go.
It should work well in practice and it allows further development. It will catch workloads which are leaking child processes by default, which is an advantage in comparison to the existing algorithm.
Both strong hierarchical approach (as in v8) and pure flat (by Johannes) are more limiting. In first case, deep hierarchies are affected (as Michal mentioned) and we stick with tree traverse policy (Tejun's point).
In second case, the further development is under a question: any new idea (say, oom_priorities, or, for example, if we will have a new useful memcg metric) should be applied to processes and memcgs simultaneously. Also, We drop any idea of memcg-level fairness and obtain some implementation issues (which I mentioned earlier). The idea of mixing tasks and memcgs leads to a much more hairy code, and the OOM code is already quite hairy. The idea of comparing killable entities is a leaking abstraction, as we can't predict how much memory killing a single process will release (say, for example, the process is the init in a pid namespace).
Quoted 9 lines
Quoted 2 lines
We need OOM behavior to kill in a deterministic order configured by policy.
And nobody is objecting to this usecase. I think we can build a priority policy on top of leaf-based decision as well. The main point we are trying to sort out here is a reasonable semantic that would work for most workloads. Sibling based selection will simply not work on those that have to use deeper hierarchies for organizational purposes. I haven't heard a counter argument for that example yet.
Yes, implementing oom_priorities is a ~15 lines patch on top of the discussing approach. David can use this small off-stream patch for now, in any case it's a step forward in comparison to the existing state.
Overall, do we have any open question left? Does anyone has any strong arguments against the discussing design?
Thanks!
Quoted 13 lines · Michal Hocko
On Tue 26-09-17 20:37:37, Tim Hockin wrote:
[...]Quoted 3 lines
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG.
I do not think we have discussed anything resembling the current approach. And I would really appreciate some more examples where decisions based on leaf nodes would be EXACTLY WRONG.
Quoted 2 lines
We need OOM behavior to kill in a deterministic order configured by policy.
Quoted 6 lines
And nobody is objecting to this usecase. I think we can build a priority policy on top of leaf-based decision as well. The main point we are trying to sort out here is a reasonable semantic that would work for most workloads. Sibling based selection will simply not work on those that have to use deeper hierarchies for organizational purposes. I haven't heard a counter argument for that example yet.
We have a priority-based, multi-user cluster. That cluster runs a variety of work, including critical things like search and gmail, as well as non-critical things like batch work. We try to offer our users an SLA around how often they will be killed by factors outside themselves, but we also want to get higher utilization. We know for a fact (data, lots of data) that most jobs have spare memory capacity, set aside for spikes or simply because accurate sizing is hard. We can sell "guaranteed" resources to critical jobs, with a high SLA. We can sell "best effort" resources to non-critical jobs with a low SLA. We achieve much better overall utilization this way.
I need to represent the priority of these tasks in a way that gives me a very strong promise that, in case of system OOM, the non-critical jobs will be chosen before the critical jobs. Regardless of size. Regardless of how many non-critical jobs have to die. I'd rather kill *all* of the non-critical jobs than a single critical job. Size of the process or cgroup is simply not a factor, and honestly given 2 options of equal priority I'd say age matters more than size.
So concretely I have 2 first-level cgroups, one for "guaranteed" and one for "best effort" classes. I always want to kill from "best effort", even if that means killing 100 small cgroups, before touching "guaranteed".
I apologize if this is not as thorough as the rest of the thread - I am somewhat out of touch with the guts of it all these days. I just feel compelled to indicate that, as a historical user (via Google systems) and current user (via Kubernetes), some of the assertions being made here do not ring true for our very real use cases. I desperately want cgroup-aware OOM handing, but it has to be policy-based or it is just not useful to us.
Thanks.
Tim
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · Tim Hockin
Quoted 13 lines · Michal Hocko
On Tue 26-09-17 20:37:37, Tim Hockin wrote:
[...]Quoted 3 lines
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG.
I do not think we have discussed anything resembling the current approach. And I would really appreciate some more examples where decisions based on leaf nodes would be EXACTLY WRONG.
Quoted 2 lines
We need OOM behavior to kill in a deterministic order configured by policy.
Quoted 7 lines
Quoted 6 lines
And nobody is objecting to this usecase. I think we can build a priority policy on top of leaf-based decision as well. The main point we are trying to sort out here is a reasonable semantic that would work for most workloads. Sibling based selection will simply not work on those that have to use deeper hierarchies for organizational purposes. I haven't heard a counter argument for that example yet.
Hi, Tim!
Quoted 10 lines
We have a priority-based, multi-user cluster. That cluster runs a variety of work, including critical things like search and gmail, as well as non-critical things like batch work. We try to offer our users an SLA around how often they will be killed by factors outside themselves, but we also want to get higher utilization. We know for a fact (data, lots of data) that most jobs have spare memory capacity, set aside for spikes or simply because accurate sizing is hard. We can sell "guaranteed" resources to critical jobs, with a high SLA. We can sell "best effort" resources to non-critical jobs with a low SLA. We achieve much better overall utilization this way.
This is well understood.
Quoted 14 lines
I need to represent the priority of these tasks in a way that gives me a very strong promise that, in case of system OOM, the non-critical jobs will be chosen before the critical jobs. Regardless of size. Regardless of how many non-critical jobs have to die. I'd rather kill *all* of the non-critical jobs than a single critical job. Size of the process or cgroup is simply not a factor, and honestly given 2 options of equal priority I'd say age matters more than size.
So concretely I have 2 first-level cgroups, one for "guaranteed" and one for "best effort" classes. I always want to kill from "best effort", even if that means killing 100 small cgroups, before touching "guaranteed".
Quoted 7 lines
I apologize if this is not as thorough as the rest of the thread - I am somewhat out of touch with the guts of it all these days. I just feel compelled to indicate that, as a historical user (via Google systems) and current user (via Kubernetes), some of the assertions being made here do not ring true for our very real use cases. I desperately want cgroup-aware OOM handing, but it has to be policy-based or it is just not useful to us.
A policy-based approach was suggested by Michal at a very beginning of this discussion. Although nobody had any strong objections against it, we've agreed that this is out of scope of this patchset.
The idea of this patchset is to introduce an ability to select a memcg as an OOM victim with the following optional killing of all belonging tasks. I believe, it's absolutely mandatory for _any_ further development of the OOM killer, which wants to deal with memory cgroups as OOM entities.
If you think that it makes impossible to support some use cases in the future, let's discuss it. Otherwise, I'd prefer to finish this part of the work, and proceed to the following improvements on top of it.
Thank you!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 69 lines · Roman Gushchin
Quoted 14 lines · Tim Hockin
Quoted 13 lines · Michal Hocko
On Tue 26-09-17 20:37:37, Tim Hockin wrote:
[...]Quoted 3 lines
I feel like David has offered examples here, and many of us at Google have offered examples as long ago as 2013 (if I recall) of cases where the proposed heuristic is EXACTLY WRONG.
I do not think we have discussed anything resembling the current approach. And I would really appreciate some more examples where decisions based on leaf nodes would be EXACTLY WRONG.
Quoted 2 lines
We need OOM behavior to kill in a deterministic order configured by policy.
Quoted 7 lines
Quoted 6 lines
And nobody is objecting to this usecase. I think we can build a priority policy on top of leaf-based decision as well. The main point we are trying to sort out here is a reasonable semantic that would work for most workloads. Sibling based selection will simply not work on those that have to use deeper hierarchies for organizational purposes. I haven't heard a counter argument for that example yet.
Hi, Tim!
Quoted 10 lines
We have a priority-based, multi-user cluster. That cluster runs a variety of work, including critical things like search and gmail, as well as non-critical things like batch work. We try to offer our users an SLA around how often they will be killed by factors outside themselves, but we also want to get higher utilization. We know for a fact (data, lots of data) that most jobs have spare memory capacity, set aside for spikes or simply because accurate sizing is hard. We can sell "guaranteed" resources to critical jobs, with a high SLA. We can sell "best effort" resources to non-critical jobs with a low SLA. We achieve much better overall utilization this way.
This is well understood.
Quoted 14 lines
I need to represent the priority of these tasks in a way that gives me a very strong promise that, in case of system OOM, the non-critical jobs will be chosen before the critical jobs. Regardless of size. Regardless of how many non-critical jobs have to die. I'd rather kill *all* of the non-critical jobs than a single critical job. Size of the process or cgroup is simply not a factor, and honestly given 2 options of equal priority I'd say age matters more than size.
So concretely I have 2 first-level cgroups, one for "guaranteed" and one for "best effort" classes. I always want to kill from "best effort", even if that means killing 100 small cgroups, before touching "guaranteed".
Quoted 7 lines
I apologize if this is not as thorough as the rest of the thread - I am somewhat out of touch with the guts of it all these days. I just feel compelled to indicate that, as a historical user (via Google systems) and current user (via Kubernetes), some of the assertions being made here do not ring true for our very real use cases. I desperately want cgroup-aware OOM handing, but it has to be policy-based or it is just not useful to us.
A policy-based approach was suggested by Michal at a very beginning of this discussion. Although nobody had any strong objections against it, we've agreed that this is out of scope of this patchset.
The idea of this patchset is to introduce an ability to select a memcg as an OOM victim with the following optional killing of all belonging tasks. I believe, it's absolutely mandatory for _any_ further development of the OOM killer, which wants to deal with memory cgroups as OOM entities.
Quoted 5 lines
If you think that it makes impossible to support some use cases in the future, let's discuss it. Otherwise, I'd prefer to finish this part of the work, and proceed to the following improvements on top of it.
Thank you!
I am 100% in favor of killing whole groups. We want that too. I just needed to express disagreement with statements that size-based decisions could not produce bad results. They can and do.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 17 lines
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
Quoted 8 lines
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
I think Tim has given very clear explanation why comparing A & D makes perfect sense. However I think the above example, a single user system where a user has designed and created the whole hierarchy and then attaches different jobs/applications to different nodes in this hierarchy, is also a valid scenario. One solution I can think of, to cater both scenarios, is to introduce a notion of 'bypass oom' or not include a memcg for oom comparision and instead include its children in the comparison.
So, in the same above example:
root
/ \
A(b) D
/ \
B CA is marked as bypass and thus B and C are to be compared to D. So, for the single user scenario, all the internal nodes are marked 'bypass oom comparison' and oom_priority of the leaves has to be set to the same value.
Below is the pseudo code of select_victim_memcg() based on this idea and David's previous pseudo code. The calculation of size of a memcg is still not very well baked here yet. I am working on it and I plan to have a patch based on Roman's v9 "mm, oom: cgroup-aware OOM killer" patch.
struct mem_cgroup *memcg = root_mem_cgroup;
struct mem_cgroup *selected_memcg = root_mem_cgroup;
struct mem_cgroup *low_memcg;
unsigned long low_priority;
unsigned long prev_badness = memcg_oom_badness(memcg); // Roman's code
LIST_HEAD(queue);next_level:
low_memcg = NULL;
low_priority = ULONG_MAX;next:
for_each_child_of_memcg(it, memcg) {
unsigned long prio = it->oom_priority;
unsigned long badness = 0;
if (it->bypass_oom && !it->oom_group &&
memcg_has_children(it)) {
list_add(&it->oom_queue, &queue);
continue;
}
if (prio > low_priority)
continue;
if (prio == low_priority) {
badness = mem_cgroup_usage(it); // for
simplicity, need more thinking
if (badness < prev_badness)
continue;
}
low_memcg = it;
low_priority = prio;
prev_badness = badness ?: mem_cgroup_usage(it); //
for simplicity
}
if (!list_empty(&queue)) {
memcg = list_last_entry(&queue, struct mem_cgroup, oom_queue);
list_del(&memcg->oom_queue);
goto next;
}
if (low_memcg) {
selected_memcg = memcg = low_memcg;
prev_badness = 0;
if (!low_memcg->oom_group)
goto next_level;
}
if (selected_memcg->oom_group)
oom_kill_memcg(selected_memcg);
else
oom_kill_process_from_memcg(selected_memcg);--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Shakeel Butt
I think Tim has given very clear explanation why comparing A & D makes perfect sense. However I think the above example, a single user system where a user has designed and created the whole hierarchy and then attaches different jobs/applications to different nodes in this hierarchy, is also a valid scenario. One solution I can think of, to cater both scenarios, is to introduce a notion of 'bypass oom' or not include a memcg for oom comparision and instead include its children in the comparison.
I'm not catching up to this thread because I don't use memcg. But if there are multiple scenarios, what about offloading memcg OOM handling to loadable kernel modules (like there are many filesystems which are called by VFS interface) ? We can do try and error more casually.
Michal Hocko
maintainerQuoted 26 lines · Shakeel Butt
Quoted 17 lines
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
Quoted 8 lines
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
Quoted 5 lines
I think Tim has given very clear explanation why comparing A & D makes perfect sense. However I think the above example, a single user system where a user has designed and created the whole hierarchy and then attaches different jobs/applications to different nodes in this hierarchy, is also a valid scenario.
Yes and nobody is disputing that, really. I guess the main disconnect here is that different people want to have more detailed control over the victim selection while the patchset tries to handle the most simplistic scenario when a no userspace control over the selection is required. And I would claim that this will be a last majority of setups and we should address it first.
A more fine grained control needs some more thinking to come up with a sensible and long term sustainable API. Just look back and see at the oom_score_adj story and how it ended up unusable in the end (well apart from never/always kill corner cases). Let's not repeat that again now.
I strongly believe that we can come up with something - be it priority based, BFP based or module based selection. But let's start simple with the most basic scenario first with a most sensible semantic implemented.
I believe the latest version (v9) looks sensible from the semantic point of view and we should focus on making it into a mergeable shape.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 40 lines · Michal Hocko
Quoted 26 lines · Shakeel Butt
Quoted 17 lines
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
Quoted 8 lines
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
Quoted 5 lines
I think Tim has given very clear explanation why comparing A & D makes perfect sense. However I think the above example, a single user system where a user has designed and created the whole hierarchy and then attaches different jobs/applications to different nodes in this hierarchy, is also a valid scenario.
Yes and nobody is disputing that, really. I guess the main disconnect here is that different people want to have more detailed control over the victim selection while the patchset tries to handle the most simplistic scenario when a no userspace control over the selection is required. And I would claim that this will be a last majority of setups and we should address it first.
Quoted 8 lines
A more fine grained control needs some more thinking to come up with a sensible and long term sustainable API. Just look back and see at the
oom_score_adjstory and how it ended up unusable in the end (well apart from never/always kill corner cases). Let's not repeat that again now.I strongly believe that we can come up with something - be it priority based, BFP based or module based selection. But let's start simple with the most basic scenario first with a most sensible semantic implemented.
Totally agree.
Quoted 2 lines
I believe the latest version (v9) looks sensible from the semantic point of view and we should focus on making it into a mergeable shape.
The only thing is that after some additional thinking I don't think anymore that implicit propagation of oom_group is a good idea.
Let me explain: assume we have memcg A with memory.max and memory.oom_group set, and nested memcg A/B with memory.max set. Let's imagine we have an OOM event if A/B. What is an expected system behavior?
We have OOM scoped to A/B, and any action should be also scoped to A/B. We really shouldn't touch processes which are not belonging to A/B. That means we should either kill the biggest process in A/B, either all processes in A/B. It's natural to make A/B/memory.oom_group responsible for this decision. It's strange to make the depend on A/memory.oom_group, IMO. It really makes no sense, and makes oom_group knob really hard to describe.
Also, after some off-list discussion, we've realized that memory.oom_knob should be delegatable. The workload should have control over it to express dependency between processes.
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 1 line · Roman Gushchin
On Mon, Oct 02, 2017 at 02:24:34PM +0200, Michal Hocko wrote:
[...]
Quoted 5 lines
Quoted 2 lines
I believe the latest version (v9) looks sensible from the semantic point of view and we should focus on making it into a mergeable shape.
The only thing is that after some additional thinking I don't think anymore that implicit propagation of
oom_groupis a good idea.
It would be better to discuss this under the v9 thread. This one is already quite convoluted IMHO.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 6 lines
Yes and nobody is disputing that, really. I guess the main disconnect here is that different people want to have more detailed control over the victim selection while the patchset tries to handle the most simplistic scenario when a no userspace control over the selection is required. And I would claim that this will be a last majority of setups and we should address it first.
IMHO the disconnect/disagreement is which memcgs should be compared with each other for oom victim selection. Let's forget about oom priority and just take size into the account. Should the oom selection algorithm, compare the leaves of the hierarchy or should it compare siblings? For the single user system, comparing leaves makes sense while in a multi user system, siblings should be compared for victim selection.
Coming back to the same example:
root
/ \
A D
/ \B C
Let's view it as a multi user system and some central job scheduler has asked a node controller on this system to start two jobs 'A' & 'D'. 'A' then went on to create sub-containers. Now, on system oom, IMO the most simple sensible thing to do from the semantic point of view is to compare 'A' and 'D' and if 'A''s usage is higher then killall 'A' if oom_group or recursively find victim memcg taking 'A' as root.
I have noted before that for single user systems, comparing 'B', 'C' & 'D' is the most sensible thing to do.
Now, in the multi user system, I can kind of force the comparison of 'A' & 'D' by setting oom_group on 'A'. IMO that is abuse of 'oom_group' as it will get double meanings/semantics which are comparison leader and killall. I would humbly suggest to have two separate notions instead. Let's say oom_gang (if you prefer just 'oom_group' is fine too) and killall.
For the single user system example, 'B', 'C' and 'D' will have 'oom_gang' set and if the user wants killall semantics too, he can set it separately.
For the multi user, 'A' and 'D' will have 'oom_gang' set. Now, lets say 'A' was selected on system oom, if 'killall' was set on 'A' then 'A' will be selected as victim otherwise the oom selection algorithm will recursively take 'A' as root and try to find victim memcg.
Another major semantic of 'oom_gang' is that the leaves will always be treated as 'oom_gang'.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 7 lines · Shakeel Butt
Quoted 6 lines
Yes and nobody is disputing that, really. I guess the main disconnect here is that different people want to have more detailed control over the victim selection while the patchset tries to handle the most simplistic scenario when a no userspace control over the selection is required. And I would claim that this will be a last majority of setups and we should address it first.
Quoted 7 lines
IMHO the disconnect/disagreement is which memcgs should be compared with each other for oom victim selection. Let's forget about oom priority and just take size into the account. Should the oom selection algorithm, compare the leaves of the hierarchy or should it compare siblings? For the single user system, comparing leaves makes sense while in a multi user system, siblings should be compared for victim selection.
THis is simply not true. This is not about single vs. multi user systems. This is about how the memcg hierarchy is organized (please have a look at the example I've provided previously). I would dare to claim that comparing siblings is a weaker semantic just because it puts stronger constrains on how the hierarchy is organized. Especially when the cgrou v2 is single hierarchy based (so we cannot create intermediate cgroup nodes for other controllers because we would automatically get a cumulative memory consumption).
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your oom_gang or others.
I am sorry but I would really appreciate to focus on making the step 1 done before diverging into details about potential improvements and a better control over the selection. This whole thing is an opt-in so there is a no risk of a regression.
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.
In the Roman's proposed solution we can already force the comparison of intermediate nodes using 'oom_group', I am just requesting to separate the killall semantics from it.
Michal Hocko
maintainerQuoted 9 lines · Shakeel Butt
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
oom_group _is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you mean
Signature · 2 lines
Michal Hocko SUSE Labs
In the example above:
root
/ \
A D
/ \B C
Does oom_group allow me to express "compare A and D; if A is chosen compare B and C; kill the loser" ? As I understand the proposal (from reading thread, not patch) it does not.
Quoted 17 lines · Michal Hocko
Quoted 9 lines · Shakeel Butt
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
oom_group_is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you mean--
Michal Hocko
SUSE Labs
Michal Hocko
maintainerQuoted 11 lines · Tim Hockin
In the example above:
root / \ A D / \B C
Does
oom_groupallow me to express "compare A and D; if A is chosen compare B and C; kill the loser" ? As I understand the proposal (from reading thread, not patch) it does not.
No it doesn't. It allows you to kill A (recursively) as the largest memory consumer. So, no, it cannot be used for prioritization, but again this is not yet the scope of the proposed solution.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Tim Hockin
In the example above:
root / \ A D / \B C
Does
oom_groupallow me to express "compare A and D; if A is chosen compare B and C; kill the loser" ? As I understand the proposal (from reading thread, not patch) it does not.
It will let you compare A and D and if A is chosen then kill A, B and C.
Quoted 24 lines · Michal Hocko
Quoted 2 lines · Shakeel Butt
Quoted 1 line
Quoted 1 line
I am sorry to cut the rest of your proposal because it simply goes
over
Quoted 1 line
Quoted 1 line
Quoted 1 line
the scope of the proposed solution while the usecase you are
mentioning
Quoted 1 line
Quoted 1 line
Quoted 1 line
is still possible. If we want to compare intermediate nodes (which
seems
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be the case) then we can always provide a knob to opt-in - be it
your
Quoted 12 lines
Quoted 5 lines
Quoted 1 line
oom_gangor others.In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
oom_group_is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you mean--
Michal Hocko
SUSE Labs
(Replying again as format of previous reply got messed up).
Quoted 11 lines · Tim Hockin
In the example above:
root / \ A D / \B C
Does
oom_groupallow me to express "compare A and D; if A is chosen compare B and C; kill the loser" ? As I understand the proposal (from reading thread, not patch) it does not.
It will let you compare A and D and if A is chosen then kill A, B and C.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Michal Hocko
Quoted 6 lines · Shakeel Butt
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.
Quoted 7 lines
Quoted 3 lines
In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
oom_group_is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you mean
I am saying decouple the notion of comparable entities and killable entities.
Johannes Weiner
maintainerQuoted 12 lines · Shakeel Butt
Quoted 11 lines · Michal Hocko
Quoted 9 lines · Shakeel Butt
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
Quoted 5 lines
Quoted 3 lines
oom_group_is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you meanI am saying decouple the notion of comparable entities and killable entities.
Feel free to send patches in a new thread.
We don't need this level of control for this series to be useful - to us, and other users. It can easily be added on top of Roman's work.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 12 lines · Shakeel Butt
Quoted 11 lines · Michal Hocko
Quoted 9 lines · Shakeel Butt
Quoted 5 lines
I am sorry to cut the rest of your proposal because it simply goes over the scope of the proposed solution while the usecase you are mentioning is still possible. If we want to compare intermediate nodes (which seems to be the case) then we can always provide a knob to opt-in - be it your
oom_gangor others.In the Roman's proposed solution we can already force the comparison of intermediate nodes using '
oom_group', I am just requesting to separate the killall semantics from it.
Quoted 5 lines
Quoted 3 lines
oom_group_is_ about killall semantic. And comparing killable entities is just a natural thing to do. So I am not sure what you meanI am saying decouple the notion of comparable entities and killable entities.
There is no strong (bijection) relation there. Right now killable entities are comparable (which I hope we agree is the right thing to do) but nothing really prevents even non-killable entities to be compared in the future.
Signature · 2 lines
Michal Hocko SUSE Labs
David Rientjes
reviewerQuoted 21 lines · Johannes Weiner
Quoted 4 lines
True but we want to have the semantic reasonably understandable. And it is quite hard to explain that the oom killer hasn't selected the largest memcg just because it happened to be in a deeper hierarchy which has been configured to cover a different resource.
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
Quoted 8 lines
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
No, I agree that we shouldn't compare sibling memory cgroups based on different criteria depending on whether group_oom is set or not.
I think it would be better to compare siblings based on the same criteria independent of group_oom if the user has mounted the hierarchy with the new mode (I think we all agree that the mount option is needed). It's very easy to describe to the user and the selection is simple to understand. Then, once a cgroup has been chosen as the victim cgroup, kill the process with the highest badness, allowing the user to influence that with /proc/pid/oom_score_adj just as today, if group_oom is disabled; otherwise, kill all eligible processes if enabled.
That, to me, is a very clear semantic and I believe it addresses Roman's usecase. My desire to have oom priorities amongst siblings is so that userspace can influence which cgroup is chosen, just as it can influence which process is chosen.
I see group_oom as a mechanism to be used when victim selection has already been done instead of something that should be considered in the policy of victim selection.
Quoted 14 lines
Let's consider an extreme case of this conundrum:
root / \ A B /|\ |A1-A1000 B1
Again we find:
- A > B
- A1 to A1000 and B1 are oomgroups
But:
- A1 to A1000 individually are tiny, B1 is huge
Quoted 7 lines
Going level by level, we'd pick A as the bigger hierarchy in the system, and then kill off one of the tiny groups A1 to A1000.
Conversely, going for biggest consumer regardless of hierarchy, we'd compare A1 to A1000 and B1, then pick B1 as the biggest single atomic memory consumer in the system and kill all its tasks.
If we compare sibling memcgs independent of group_oom, we don't necessarily pick A unless it really is larger than B.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Michal Hocko
maintainerQuoted 32 lines · David Rientjes
Quoted 21 lines · Johannes Weiner
Quoted 4 lines
True but we want to have the semantic reasonably understandable. And it is quite hard to explain that the oom killer hasn't selected the largest memcg just because it happened to be in a deeper hierarchy which has been configured to cover a different resource.
Going back to Michal's example, say the user configured the following:
root / \ A D / \B C
A global OOM event happens and we find this:
- A > D
- B, C, D are oomgroupsWhat the user is telling us is that B, C, and D are compound memory consumers. They cannot be divided into their task parts from a memory point of view.
Quoted 8 lines
However, the user doesn't say the same for A: the A subtree summarizes and controls aggregate consumption of B and C, but without groupoom set on A, the user says that A is in fact divisible into independent memory consumers B and C.
If we don't have to kill all of A, but we'd have to kill all of D, does it make sense to compare the two?
Quoted 8 lines
No, I agree that we shouldn't compare sibling memory cgroups based on different criteria depending on whether
group_oomis set or not.I think it would be better to compare siblings based on the same criteria independent of
group_oomif the user has mounted the hierarchy with the new mode (I think we all agree that the mount option is needed). It's very easy to describe to the user and the selection is simple to understand.
I disagree. Just take the most simplistic example when cgroups reflect some other higher level organization - e.g. school with teachers, students and admins as the top level cgroups to control the proper cpu share load. Now you want to have a fair OOM selection between different entities. Do you consider selecting students all the time as an expected behavior just because their are the largest group? This just doesn't make any sense to me.
Quoted 4 lines
Then, once a cgroup has been chosen as the victim cgroup,
kill the process with the highest badness, allowing the user to influence that with/proc/pid/oom_score_adjjust as today, ifgroup_oomis disabled; otherwise, kill all eligible processes if enabled.
And now, what should be the semantic of group_oom on an intermediate (non-leaf) memcg? Why should we compare it to other killable entities? Roman was mentioning a setup where a _single_ workload consists of a deeper hierarchy which has to be shut down at once. It absolutely makes sense to consider the cumulative memory of that hierarchy when we are going to kill it all.
Quoted 4 lines
That, to me, is a very clear semantic and I believe it addresses Roman's usecase. My desire to have oom priorities amongst siblings is so that userspace can influence which cgroup is chosen, just as it can influence which process is chosen.
But what you are proposing is something different from oom_score_adj. That only sets bias to the killable entities while priorities on intermediate non-killable memcgs controls how the whole oom hierarchy is traversed. So a non-killable intermediate memcg can hugely influence what gets killed in the end. This is IMHO a tricky and I would even dare to claim a wrong semantic. I can see priorities being very useful on killable entities for sure. I am not entirely sure what would be the best approach yet and that is why I've suggested that to postpone to after we settle with a simple approach first. Bringing priorities back to the discussion again will not help to move that forward I am afraid.
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 9 lines · Michal Hocko
Quoted 8 lines
No, I agree that we shouldn't compare sibling memory cgroups based on different criteria depending on whether
group_oomis set or not.I think it would be better to compare siblings based on the same criteria independent of
group_oomif the user has mounted the hierarchy with the new mode (I think we all agree that the mount option is needed). It's very easy to describe to the user and the selection is simple to understand.
Quoted 8 lines
I disagree. Just take the most simplistic example when cgroups reflect some other higher level organization - e.g. school with teachers, students and admins as the top level cgroups to control the proper cpu share load. Now you want to have a fair OOM selection between different entities. Do you consider selecting students all the time as an expected behavior just because their are the largest group? This just doesn't make any sense to me.
Are you referring to this?
root
/ \
students admins
/ \ / \
A B C DIf the cumulative usage of all students exceeds the cumulative usage of all admins, yes, the choice is to kill from the /students tree. This has been Roman's design from the very beginning. If the preference is to kill the single largest process, which may be attached to either subtree, you would not have opted-in to the new heuristic.
Quoted 5 lines
Quoted 4 lines
Then, once a cgroup has been chosen as the victim cgroup,
kill the process with the highest badness, allowing the user to influence that with/proc/pid/oom_score_adjjust as today, ifgroup_oomis disabled; otherwise, kill all eligible processes if enabled.
Quoted 7 lines
And now, what should be the semantic of
group_oomon an intermediate (non-leaf) memcg? Why should we compare it to other killable entities? Roman was mentioning a setup where a _single_ workload consists of a deeper hierarchy which has to be shut down at once. It absolutely makes sense to consider the cumulative memory of that hierarchy when we are going to kill it all.
If group_oom is enabled on an intermediate memcg, I think the intuitive way to handle it would be that all descendants are also implicitly or explicitly group_oom. It is compared to sibling cgroups based on cumulative usage at the time of oom and the largest is chosen and iterated. The point is to separate out the selection heuristic (policy) from group_oom (mechanism) so that we don't bias or prefer subtrees based on group_oom, which makes this much more complex.
Quoted 5 lines
But what you are proposing is something different from
oom_score_adj. That only sets bias to the killable entities while priorities on intermediate non-killable memcgs controls how the whole oom hierarchy is traversed. So a non-killable intermediate memcg can hugely influence what gets killed in the end.
Why is there an intermediate non-killable memcg allowed? Cgroup oom priorities should not be allowed to disable oom killing, it should only set a priority. The only reason an intermediate cgroup should be non-killable is if there are no processes attached, but I don't think anyone is arguing we should just do nothing in that scenario. The point is that the user has infleunce over the decisionmaking with a per-process heuristic with oom_score_adj and should also have influence over the decisionmaking with a per-cgroup heuristic.
Quoted 7 lines
This is IMHO a tricky and I would even dare
to claim a wrong semantic. I can see priorities being very useful on killable entities for sure. I am not entirely sure what would be the best approach yet and that is why I've suggested that to postpone to after we settle with a simple approach first. Bringing priorities back to the discussion again will not help to move that forward I am afraid.
I agree to keep it as simple as possible, especially since some users want specific victim selection, it should be clear to document, and it shouldn't be influenced by some excessive amount of usage in another subtree the user has no control over (/admins over /students) to prevent the user from defining that it really wants to be the first oom victim or the admin from defining it really prefers something else killed first.
My suggestion is that Roman's implementation is clear, well defined, and has real-world usecases and it should be the direction that this moves in. I think victim selection and group_oom are distinct and should not influence the decisionmaking. I think that oom_priority should influence the decisionmaking.
When mounted with the new option, as the oom hierarchy is iterated, compare all sibling cgroups regarding cumulative size unless an oom priority overrides that (either user specifying it wants to be oom killed or admin specifying it prefers something else). When a victim memcg is chosen, use group_oom to determine what should be killed, otherwise choose by oom_score_adj. I can't imagine how this can be any simpler.
Michal Hocko
maintainerQuoted 22 lines · David Rientjes
Quoted 9 lines · Michal Hocko
Quoted 8 lines
No, I agree that we shouldn't compare sibling memory cgroups based on different criteria depending on whether
group_oomis set or not.I think it would be better to compare siblings based on the same criteria independent of
group_oomif the user has mounted the hierarchy with the new mode (I think we all agree that the mount option is needed). It's very easy to describe to the user and the selection is simple to understand.Quoted 8 lines
I disagree. Just take the most simplistic example when cgroups reflect some other higher level organization - e.g. school with teachers, students and admins as the top level cgroups to control the proper cpu share load. Now you want to have a fair OOM selection between different entities. Do you consider selecting students all the time as an expected behavior just because their are the largest group? This just doesn't make any sense to me.
Are you referring to this?
Quoted 8 lines
root / \ students admins / \ / \ A B C DIf the cumulative usage of all students exceeds the cumulative usage of all admins, yes, the choice is to kill from the /students tree.
Which is wrong IMHO because the number of stutends is likely much more larger than admins (or teachers) yet it might be the admins one to run away. This example simply shows how comparing siblinks highly depends on the way you organize the hierarchy rather than the actual memory consumer runaways which is the primary goal of the OOM killer to handle.
Quoted 1 line
This has been Roman's design from the very beginning.
I suspect this was the case because deeper hierarchies for organizational purposes haven't been considered.
Quoted 3 lines
If the preference is to kill
the single largest process, which may be attached to either subtree, you would not have opted-in to the new heuristic.
I believe you are making a wrong assumption here. The container cleanup is sound reason to opt in and deeper hierarchies are simply required in the cgroup v2 world where you do not have separate hierarchies.
Quoted 13 lines
Quoted 5 lines
Quoted 4 lines
Then, once a cgroup has been chosen as the victim cgroup,
kill the process with the highest badness, allowing the user to influence that with/proc/pid/oom_score_adjjust as today, ifgroup_oomis disabled; otherwise, kill all eligible processes if enabled.Quoted 7 lines
And now, what should be the semantic of
group_oomon an intermediate (non-leaf) memcg? Why should we compare it to other killable entities? Roman was mentioning a setup where a _single_ workload consists of a deeper hierarchy which has to be shut down at once. It absolutely makes sense to consider the cumulative memory of that hierarchy when we are going to kill it all.
Quoted 3 lines
If
group_oomis enabled on an intermediate memcg, I think the intuitive way to handle it would be that all descendants are also implicitly or explicitlygroup_oom.
This is an interesting point. I would tend to agree here. If somebody requires all-in clean up up the hierarchy it feels strange that a subtree would disagree (e.g. during memcg oom on the subtree). I can hardly see a usecase that would really need a different group_oom policy depending on where in the hierarchy the oom happened to be honest. Roman?
Quoted 5 lines
It is compared to sibling cgroups based on
cumulative usage at the time of oom and the largest is chosen and iterated. The point is to separate out the selection heuristic (policy) fromgroup_oom(mechanism) so that we don't bias or prefer subtrees based ongroup_oom, which makes this much more complex.
I disagree. group_oom determines killable entity and making a decision based on a non-killable entities is weird as already pointed out.
Signature · 2 lines
Michal Hocko SUSE Labs
Roman Gushchin
AppliedQuoted 68 lines · Michal Hocko
Quoted 22 lines · David Rientjes
Quoted 9 lines · Michal Hocko
Quoted 8 lines
No, I agree that we shouldn't compare sibling memory cgroups based on different criteria depending on whether
group_oomis set or not.I think it would be better to compare siblings based on the same criteria independent of
group_oomif the user has mounted the hierarchy with the new mode (I think we all agree that the mount option is needed). It's very easy to describe to the user and the selection is simple to understand.Quoted 8 lines
I disagree. Just take the most simplistic example when cgroups reflect some other higher level organization - e.g. school with teachers, students and admins as the top level cgroups to control the proper cpu share load. Now you want to have a fair OOM selection between different entities. Do you consider selecting students all the time as an expected behavior just because their are the largest group? This just doesn't make any sense to me.
Are you referring to this?
Quoted 8 lines
root / \ students admins / \ / \ A B C DIf the cumulative usage of all students exceeds the cumulative usage of all admins, yes, the choice is to kill from the /students tree.
Which is wrong IMHO because the number of stutends is likely much more larger than admins (or teachers) yet it might be the admins one to run away. This example simply shows how comparing siblinks highly depends on the way you organize the hierarchy rather than the actual memory consumer runaways which is the primary goal of the OOM killer to handle.
Quoted 1 line
This has been Roman's design from the very beginning.
I suspect this was the case because deeper hierarchies for organizational purposes haven't been considered.
Quoted 3 lines
If the preference is to kill
the single largest process, which may be attached to either subtree, you would not have opted-in to the new heuristic.I believe you are making a wrong assumption here. The container cleanup is sound reason to opt in and deeper hierarchies are simply required in the cgroup v2 world where you do not have separate hierarchies.
Quoted 13 lines
Quoted 5 lines
Quoted 4 lines
Then, once a cgroup has been chosen as the victim cgroup,
kill the process with the highest badness, allowing the user to influence that with/proc/pid/oom_score_adjjust as today, ifgroup_oomis disabled; otherwise, kill all eligible processes if enabled.Quoted 7 lines
And now, what should be the semantic of
group_oomon an intermediate (non-leaf) memcg? Why should we compare it to other killable entities? Roman was mentioning a setup where a _single_ workload consists of a deeper hierarchy which has to be shut down at once. It absolutely makes sense to consider the cumulative memory of that hierarchy when we are going to kill it all.Quoted 3 lines
If
group_oomis enabled on an intermediate memcg, I think the intuitive way to handle it would be that all descendants are also implicitly or explicitlygroup_oom.
Quoted 6 lines
This is an interesting point. I would tend to agree here. If somebody requires all-in clean up up the hierarchy it feels strange that a subtree would disagree (e.g. during memcg oom on the subtree). I can hardly see a usecase that would really need a different
group_oompolicy depending on where in the hierarchy the oom happened to be honest. Roman?
Yes, I'd say that it's strange to apply settings from outside the OOMing cgroup to the subtree, but actually it's not. The oom_group setting should basically mean that the OOM killer will not kill a random task in the subtree. And it doesn't matter if it was global or memcg-wide OOM.
Applied to v9. Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Johannes Weiner
maintainerQuoted 9 lines · David Rientjes
Quoted 6 lines · Roman Gushchin
This patchset makes the OOM killer cgroup-aware.
v8:
- Do not kill tasks withOOM_SCORE_ADJ-1000
- Make the whole thing opt-in with cgroup mount option control
- Dropoom_priorityfor further discussions
Quoted 10 lines
Nack, we specifically require
oom_priorityfor this to function correctly, otherwise we cannot prefer to kill from low priority leaf memcgs as required. v8 appears to implement new functionality that we want, to compare two memcgs based on usage, but without the ability to influence that decision to protect important userspace, so now I'm in a position where (1) nothing has changed if I don't use the new mount option or (2) I get completely different oom kill selection with the new mount option but not the ability to influence it. I was much happier with the direction that v7 was taking, but since v8 causes us to regress without the ability to change memcg priority, this has to be nacked.
That's a ridiculous nak.
The fact that this patch series doesn't solve your particular problem is not a technical argument to *reject* somebody else's work to solve a different problem. It's not a regression when behavior is completely unchanged unless you explicitly opt into a new functionality.
So let's stay reasonable here.
The patch series has merit as it currently stands. It makes OOM killing in a cgrouped system fairer and less surprising. Whether you have the ability to influence this in a new way is an entirely separate discussion. It's one that involves ABI and user guarantees.
Right now Roman's patches make no guarantees on how the cgroup tree is descended. But once we define an interface for prioritization, it locks the victim algorithm into place to a certain extent.
It also involves a discussion about how much control userspace should have over OOM killing in the first place. It's a last-minute effort to save the kernel from deadlocking on memory. Whether that is the time and place to have userspace make clever resource management decisions is an entirely different thing than what Roman is doing.
But this patch series doesn't prevent any such future discussion and implementations, and it's not useless without it. So let's not conflate these two things, and hold the priority patch for now.
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 9 lines · Johannes Weiner
That's a ridiculous nak.
The fact that this patch series doesn't solve your particular problem is not a technical argument to *reject* somebody else's work to solve a different problem. It's not a regression when behavior is completely unchanged unless you explicitly opt into a new functionality.
So let's stay reasonable here.
The issue is that if you opt-in to the new feature, then you are forced to change /proc/pid/oom_score_adj of all processes attached to a cgroup that you do not want oom killed based on size to be oom disabled. The kernel provides no other remedy without oom priorities since the new feature would otherwise disregard oom_score_adj. In that case, userspace is racing in two ways: (1) attach of process to a memcg you want to protect from oom kill (first class, vital, large memory hog job) to set to oom disable and (2) adjustment of other cgroups to make them eligible after first oom kill.
It doesn't have anything to do with my particular usecase, but rather the ability of userspace to influence the decisions of the kernel. Previous to this patchset, when selection is done based on process size, userspace has full control over selection. After this patchset, userspace has no control other than setting all processes to be oom disabled if the largest memory consumer is to be protected. Roman's memory.oom_priority provides a perfect solution for userspace to be able to influence this decision making and causes no change in behavior for users who choose not to tune memory.oom_priority. The nack originates from the general need for userspace influence over oom victim selection and to avoid userspace needing to take the rather drastic measure of setting all processes to be oom disabled to prevent oom kill in kernels before oom priorities are introduced.
Quoted 9 lines
The patch series has merit as it currently stands. It makes OOM killing in a cgrouped system fairer and less surprising. Whether you have the ability to influence this in a new way is an entirely separate discussion. It's one that involves ABI and user guarantees.
Right now Roman's patches make no guarantees on how the cgroup tree is descended. But once we define an interface for prioritization, it locks the victim algorithm into place to a certain extent.
The patchset compares memory cgroup size relative to sibling cgroups only, the same comparison for memory.oom_priority. There is a guarantee provided on how cgroup size is compared in select_victim_memcg(), it hierarchically accumulates the "size" from leaf nodes up to the root memcg and then iterates the tree comparing sizes between sibling cgroups to choose a victim memcg. That algorithm could be more elaborately described in the documentation, but we simply cannot change the implementation of select_victim_memcg() later even without oom priorities since users cannot get inconsistent results after opting into a feature between kernel versions. I believe the selection criteria should be implemented to be deterministic, as select_victim_memcg() does, and the documentation should fully describe what the selection criteria is, and then allow the user to decide.
Quoted 10 lines
It also involves a discussion about how much control userspace should have over OOM killing in the first place. It's a last-minute effort to save the kernel from deadlocking on memory. Whether that is the time and place to have userspace make clever resource management decisions is an entirely different thing than what Roman is doing.
But this patch series doesn't prevent any such future discussion and implementations, and it's not useless without it. So let's not conflate these two things, and hold the priority patch for now.
Roman is planning on introducing memory.oom_priority back into the patchset per https://marc.info/?l=linux-kernel&m=150574701126877 and I agree with the very clear semantic that it introduces: to have the size-based comparison use the same rules as the userspace priority comparison. It's very powerful and I'm happy to ack the final version that he plans on posting.
Johannes Weiner
maintainerQuoted 9 lines · David Rientjes
Quoted 7 lines · Johannes Weiner
That's a ridiculous nak.
The fact that this patch series doesn't solve your particular problem is not a technical argument to *reject* somebody else's work to solve a different problem. It's not a regression when behavior is completely unchanged unless you explicitly opt into a new functionality.
Quoted 6 lines
Quoted 2 lines
So let's stay reasonable here.
The issue is that if you opt-in to the new feature, then you are forced to change
/proc/pid/oom_score_adjof all processes attached to a cgroup that you do not want oom killed based on size to be oom disabled.
You're assuming that most people would want to influence the oom behavior in the first place. I think the opposite is the case: most people don't care as long as the OOM killer takes the intent the user has expressed wrt runtime containerization/grouping into account.
Quoted 2 lines
The kernel provides no other remedy without oom priorities since the new feature would otherwise disregard
oom_score_adj.
As of v8, it respects this setting and doesn't kill min score tasks.
Quoted 4 lines
The nack originates from the general need for userspace influence over oom victim selection and to avoid userspace needing to take the rather drastic measure of setting all processes to be oom disabled to prevent oom kill in kernels before oom priorities are introduced.
As I said, we can discuss this in a separate context. Because again, I really don't see how the lack of configurability in an opt-in feature would diminish its value for many people who don't even care to adjust and influence this behavior.
Quoted 10 lines
Quoted 9 lines
The patch series has merit as it currently stands. It makes OOM killing in a cgrouped system fairer and less surprising. Whether you have the ability to influence this in a new way is an entirely separate discussion. It's one that involves ABI and user guarantees.
Right now Roman's patches make no guarantees on how the cgroup tree is descended. But once we define an interface for prioritization, it locks the victim algorithm into place to a certain extent.
Quoted 13 lines
The patchset compares memory cgroup size relative to sibling cgroups only, the same comparison for memory.oom_priority. There is a guarantee provided on how cgroup size is compared in
select_victim_memcg(), it hierarchically accumulates the "size" from leaf nodes up to the root memcg and then iterates the tree comparing sizes between sibling cgroups to choose a victim memcg. That algorithm could be more elaborately described in the documentation, but we simply cannot change the implementation ofselect_victim_memcg()later even without oom priorities since users cannot get inconsistent results after opting into a feature between kernel versions. I believe the selection criteria should be implemented to be deterministic, asselect_victim_memcg()does, and the documentation should fully describe what the selection criteria is, and then allow the user to decide.
I wholeheartedly disagree. We have changed the behavior multiple times in the past. In fact, you have arguably done the most drastic changes to the algorithm since the OOM killer was first introduced. E.g.
a63d83f427fb oom: badness heuristic rewrite
And that's completely fine. Because this thing is not a resource management tool for userspace, it's the kernel saving itself. At best in a manner that's not too surprising to userspace.
To me, your argument behind the NAK still boils down to "this doesn't support my highly specialized usecase." But since it doesn't prohibit your usecase - which isn't even supported upstream, btw - this really doesn't carry much weight.
I'd say if you want configurability on top of Roman's code, please submit patches and push the case for these in a separate effort.
Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
David Rientjes
reviewerQuoted 9 lines · Johannes Weiner
Quoted 3 lines
The issue is that if you opt-in to the new feature, then you are forced to change
/proc/pid/oom_score_adjof all processes attached to a cgroup that you do not want oom killed based on size to be oom disabled.You're assuming that most people would want to influence the oom behavior in the first place. I think the opposite is the case: most people don't care as long as the OOM killer takes the intent the user has expressed wrt runtime containerization/grouping into account.
If you do not want to influence the oom behavior, do not change memory.oom_priority from its default. It's that simple.
Quoted 5 lines
Quoted 2 lines
The kernel provides no other remedy without oom priorities since the new feature would otherwise disregard
oom_score_adj.As of v8, it respects this setting and doesn't kill min score tasks.
That's the issue. To protect a memory cgroup from being oom killed in a system oom condition, you need to change oom_score_adj of *all* processes attached to be oom disabled. Then, you have a huge problem in memory cgroup oom conditions because nothing can be killed in that hierarchy itself.
Quoted 18 lines
Quoted 5 lines
The patchset compares memory cgroup size relative to sibling cgroups only, the same comparison for memory.oom_priority. There is a guarantee provided on how cgroup size is compared in
select_victim_memcg(), it hierarchically accumulates the "size" from leaf nodes up to the root memcg and then iterates the tree comparing sizes between sibling cgroups toQuoted 8 lines
choose a victim memcg. That algorithm could be more elaborately described in the documentation, but we simply cannot change the implementation of
select_victim_memcg()later even without oom priorities since users cannot get inconsistent results after opting into a feature between kernel versions. I believe the selection criteria should be implemented to be deterministic, asselect_victim_memcg()does, and the documentation should fully describe what the selection criteria is, and then allow the user to decide.I wholeheartedly disagree. We have changed the behavior multiple times in the past. In fact, you have arguably done the most drastic changes to the algorithm since the OOM killer was first introduced. E.g.
Quoted 6 lines
a63d83f427fboom: badness heuristic rewriteAnd that's completely fine. Because this thing is not a resource management tool for userspace, it's the kernel saving itself. At best in a manner that's not too surprising to userspace.
When I did that, I had to add /proc/pid/oom_score_adj to allow userspace to influence selection. We came up with /proc/pid/oom_score_adj when working with kde, openssh, chromium, and udev because they cared about the ability to influence the decisionmaking. I'm perfectly happy with the new heuristic presented in this patchset, I simply want userspace to be able to influence it, if it desires. Requiring userspace to set all processes to be oom disabled to protect a hierarchy is totally and completely broken. It livelocks the memory cgroup if it is oom itself.
Quoted 8 lines
To me, your argument behind the NAK still boils down to "this doesn't support my highly specialized usecase." But since it doesn't prohibit your usecase - which isn't even supported upstream, btw - this really doesn't carry much weight.
I'd say if you want configurability on top of Roman's code, please submit patches and push the case for these in a separate effort.
Roman implemented memory.oom_priority himself, it has my Tested-by, and it allows users who want to protect high priority memory cgroups from using the size based comparison for all other cgroups that we very much desire.
Tejun Heo
maintainerHello, David.
Quoted 5 lines · David Rientjes
It doesn't have anything to do with my particular usecase, but rather the ability of userspace to influence the decisions of the kernel. Previous to this patchset, when selection is done based on process size, userspace has full control over selection. After this patchset, userspace has no control other than setting all processes to be oom disabled if the largest
Quoted 8 lines
memory consumer is to be protected. Roman's memory.oom_priority provides a perfect solution for userspace to be able to influence this decision making and causes no change in behavior for users who choose not to tune memory.oom_priority. The nack originates from the general need for userspace influence over oom victim selection and to avoid userspace needing to take the rather drastic measure of setting all processes to be oom disabled to prevent oom kill in kernels before oom priorities are introduced.
Overall, I think that OOM killing is the wrong place to implement sophisticated intelligence in. It's too late to be smart - the workload already has suffered significantly and there's only very limited amount of computing which can be performed. That said, if there's a useful and general enough mechanism to configure OOM killer behavior from userland, that can definitely be useful.
Quoted 5 lines
The patchset compares memory cgroup size relative to sibling cgroups only, the same comparison for memory.oom_priority. There is a guarantee provided on how cgroup size is compared in
select_victim_memcg(), it hierarchically accumulates the "size" from leaf nodes up to the root memcg and then iterates the tree comparing sizes between sibling cgroups to
Quoted 8 lines
choose a victim memcg. That algorithm could be more elaborately described in the documentation, but we simply cannot change the implementation of
select_victim_memcg()later even without oom priorities since users cannot get inconsistent results after opting into a feature between kernel versions. I believe the selection criteria should be implemented to be deterministic, asselect_victim_memcg()does, and the documentation should fully describe what the selection criteria is, and then allow the user to decide.
We even change the whole scheduling behaviors and try really hard to not get locked into specific implementation details which exclude future improvements. Guaranteeing OOM killing selection would be crazy. Why would we prevent ourselves from doing things better in the future? We aren't talking about the semantics of read(2) here. This is a kernel emergency mechanism to avoid deadlock at the last moment.
Quoted 6 lines
Roman is planning on introducing memory.oom_priority back into the patchset per https://marc.info/?l=linux-kernel&m=150574701126877 and I agree with the very clear semantic that it introduces: to have the size-based comparison use the same rules as the userspace priority comparison. It's very powerful and I'm happy to ack the final version that he plans on posting.
To me, the proposed oom_priority mechanism seems too limited and makes the error of tightly coupling the hierarchical behavior of resource distribution with OOM victim selection. They can be related but are not the same and coupling them together in the kernel interface is likely a mistake which will lead to long term pains that we can't easily get out of.
Here's a really simple use case. Imagine a system which hosts two containers of services and one is somewhat favored over the other and wants to set up cgroup hierarchy so that resources are split at the top level between the two containers. oom_priority is set accordingly too. Let's say a low priority maintenance job in higher priority container goes berserk, as they oftne do, and pushing the system into OOM.
With the proposed static oom_priority mechanism, the only configuration which can be expressed is "kill all of the lower top level subtree before any of the higher one", which is a silly restriction leading to silly behavior and a direct result of conflating resource distribution network with level-by-level OOM killing decsion.
If we want to allow users to steer OOM killing, I suspect that it should be aligned at delegation boundaries rather than on cgroup hierarchy itself. We can discuss that but it is a separate discussion.
The mechanism being proposed is fundamentally flawed. You can't push that in by nacking other improvements.
Thanks.
Signature · 1 line
tejun
David Rientjes
reviewerQuoted 14 lines · Tejun Heo
Quoted 5 lines
It doesn't have anything to do with my particular usecase, but rather the ability of userspace to influence the decisions of the kernel. Previous to this patchset, when selection is done based on process size, userspace has full control over selection. After this patchset, userspace has no control other than setting all processes to be oom disabled if the largest
Quoted 8 lines
memory consumer is to be protected. Roman's memory.oom_priority provides a perfect solution for userspace to be able to influence this decision making and causes no change in behavior for users who choose not to tune memory.oom_priority. The nack originates from the general need for userspace influence over oom victim selection and to avoid userspace needing to take the rather drastic measure of setting all processes to be oom disabled to prevent oom kill in kernels before oom priorities are introduced.
Quoted 7 lines
Overall, I think that OOM killing is the wrong place to implement sophisticated intelligence in. It's too late to be smart - the workload already has suffered significantly and there's only very limited amount of computing which can be performed. That said, if there's a useful and general enough mechanism to configure OOM killer behavior from userland, that can definitely be useful.
What is under discussion is a new way to compare sibling cgroups when selecting a victim for oom kill. It's a new heuristic based on a characteristic of the memory cgroup rather than the individual process. We want this behavior that the patchset implements. The only desire is a way for userspace to influence that decision making in the same way that /proc/pid/oom_score_adj allows userspace to influence the current heuristic.
Current heuristic based on processes is coupled with per-process /proc/pid/oom_score_adj. The proposed
heuristic has no ability to be influenced by userspace, and it needs one. The proposed heuristic based on memory cgroups coupled with Roman's per-memcg memory.oom_priority is appropriate and needed. It is not "sophisticated intelligence," it merely allows userspace to protect vital memory cgroups when opting into the new features (cgroups compared based on size and memory.oom_group) that we very much want.
Quoted 7 lines
We even change the whole scheduling behaviors and try really hard to not get locked into specific implementation details which exclude future improvements. Guaranteeing OOM killing selection would be crazy. Why would we prevent ourselves from doing things better in the future? We aren't talking about the semantics of read(2) here. This is a kernel emergency mechanism to avoid deadlock at the last moment.
We merely want to prefer other memory cgroups are oom killed on system oom conditions before important ones, regardless if the important one is using more memory than the others because of the new heuristic this patchset introduces. This is exactly the same as /proc/pid/oom_score_adj for the current heuristic.
Quoted 8 lines
Here's a really simple use case. Imagine a system which hosts two containers of services and one is somewhat favored over the other and wants to set up cgroup hierarchy so that resources are split at the top level between the two containers.
oom_priorityis set accordingly too. Let's say a low priority maintenance job in higher priority container goes berserk, as they oftne do, and pushing the system into OOM.
Quoted 7 lines
With the proposed static
oom_prioritymechanism, the only configuration which can be expressed is "kill all of the lower top level subtree before any of the higher one", which is a silly restriction leading to silly behavior and a direct result of conflating resource distribution network with level-by-level OOM killing decsion.
The problem you're describing is an issue with the top-level limits after this patchset is merged, not memory.oom_priority at all.
If they are truly split evenly, this patchset kills the largest process from the hierarchy with the most charged memory. That's unchanged if the two priorities are equal. By changing the priority to be more preferred for a hierarchy, you indeed prefer oom kills from the lower priority hierarchy. You've opted in. One hierarchy is more important than the other, regardless of any hypothetical low priority maintenance job going berserk.
If you have this low priority maintenance job charging memory to the high priority hierarchy, you're already misconfigured unless you adjust /proc/pid/oom_score_adj because it will oom kill any larger process than itself in today's kernels anyway.
A better configuration would be attach this hypothetical low priority maintenance job to its own sibling cgroup with its own memory limit to avoid exactly that problem: it going berserk and charging too much memory to the high priority container that results in one of its processes getting oom killed.
Tejun Heo
maintainerHello,
Quoted 5 lines · David Rientjes
Current heuristic based on processes is coupled with per-process
/proc/pid/oom_score_adj. The proposed
heuristic has no ability to be influenced by userspace, and it needs one. The proposed heuristic based on memory cgroups coupled with Roman's per-memcg memory.oom_priority is appropriate and needed. It is not
So, this is where we disagree. I don't think it's a good design.
Quoted 3 lines
"sophisticated intelligence," it merely allows userspace to protect vital memory cgroups when opting into the new features (cgroups compared based on size and memory.oom_group) that we very much want.
which can't achieve that goal very well for wide variety of users.
Quoted 7 lines
Quoted 6 lines
We even change the whole scheduling behaviors and try really hard to not get locked into specific implementation details which exclude future improvements. Guaranteeing OOM killing selection would be crazy. Why would we prevent ourselves from doing things better in the future? We aren't talking about the semantics of read(2) here. This is a kernel emergency mechanism to avoid deadlock at the last moment.
Quoted 5 lines
We merely want to prefer other memory cgroups are oom killed on system oom conditions before important ones, regardless if the important one is using more memory than the others because of the new heuristic this patchset introduces. This is exactly the same as
/proc/pid/oom_score_adjfor the current heuristic.
You were arguing that we should lock into a specific heuristics and guarantee the same behavior. We shouldn't.
When we introduce a user visible interface, we're making a lot of promises. My point is that we need to be really careful when making those promises.
Quoted 10 lines
If you have this low priority maintenance job charging memory to the high priority hierarchy, you're already misconfigured unless you adjust
/proc/pid/oom_score_adjbecause it will oom kill any larger process than itself in today's kernels anyway.A better configuration would be attach this hypothetical low priority maintenance job to its own sibling cgroup with its own memory limit to avoid exactly that problem: it going berserk and charging too much memory to the high priority container that results in one of its processes getting oom killed.
And how do you guarantee that across delegation boundaries? The points you raise on why the priority should be applied level-by-level are exactly the same points why this doesn't really work. OOM killing priority isn't something which can be distributed across cgroup hierarchy level-by-level. The resulting decision tree doesn't make any sense.
I'm not against adding something which works but strict level-by-level comparison isn't the solution.
Thanks.
Signature · 1 line
tejun
David Rientjes
reviewerQuoted 11 lines · Tejun Heo
Quoted 10 lines
If you have this low priority maintenance job charging memory to the high priority hierarchy, you're already misconfigured unless you adjust
/proc/pid/oom_score_adjbecause it will oom kill any larger process than itself in today's kernels anyway.A better configuration would be attach this hypothetical low priority maintenance job to its own sibling cgroup with its own memory limit to avoid exactly that problem: it going berserk and charging too much memory to the high priority container that results in one of its processes getting oom killed.
Quoted 7 lines
And how do you guarantee that across delegation boundaries? The points you raise on why the priority should be applied level-by-level are exactly the same points why this doesn't really work. OOM killing priority isn't something which can be distributed across cgroup hierarchy level-by-level. The resulting decision tree doesn't make any sense.
It works very well in practice with real world usecases, and Roman has developed the same design independently that we have used for the past four years. Saying it doesn't make any sense doesn't hold a lot of weight when we both independently designed and implemented the same solution to address our usecases.
Quoted 3 lines
I'm not against adding something which works but strict level-by-level comparison isn't the solution.
Each of the eight versions of Roman's cgroup aware oom killer has done comparisons between siblings at each level. Userspace influence on that comparison would thus also need to be done at each level. It's a very powerful combination in practice.
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>