Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1740047 > unrolled thread
| Started by | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| First post | 2017-09-26 19:30 +0200 |
| Last post | 2017-10-02 22:50 +0200 |
| Articles | 9 — 5 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [v8 0/4] cgroup-aware OOM killer Johannes Weiner <hannes@cmpxchg.org> - 2017-09-26 19:30 +0200
Re: [v8 0/4] cgroup-aware OOM killer Tim Hockin <thockin@hockin.org> - 2017-09-27 05:40 +0200
Re: [v8 0/4] cgroup-aware OOM killer Michal Hocko <mhocko@kernel.org> - 2017-09-27 09:50 +0200
Re: [v8 0/4] cgroup-aware OOM killer Tim Hockin <thockin@hockin.org> - 2017-09-27 17:40 +0200
Re: [v8 0/4] cgroup-aware OOM killer Tim Hockin <thockin@hockin.org> - 2017-09-27 20:20 +0200
Re: [v8 0/4] cgroup-aware OOM killer Shakeel Butt <shakeelb@google.com> - 2017-10-02 01:30 +0200
Re: [v8 0/4] cgroup-aware OOM killer Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2017-10-02 14:00 +0200
Re: [v8 0/4] cgroup-aware OOM killer Michal Hocko <mhocko@kernel.org> - 2017-10-02 14:30 +0200
Re: [v8 0/4] cgroup-aware OOM killer Shakeel Butt <shakeelb@google.com> - 2017-10-02 22:50 +0200
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2017-09-26 19:30 +0200 |
| Subject | Re: [v8 0/4] cgroup-aware OOM killer |
| Message-ID | <uu1Qe-7HQ-5@gated-at.bofh.it> |
On Tue, Sep 26, 2017 at 03:30:40PM +0200, Michal Hocko wrote: > On Tue 26-09-17 13:13:00, Roman Gushchin wrote: > > On Tue, Sep 26, 2017 at 01:21:34PM +0200, Michal Hocko wrote: > > > On Tue 26-09-17 11:59:25, Roman Gushchin wrote: > > > > On Mon, Sep 25, 2017 at 10:25:21PM +0200, Michal Hocko wrote: > > > > > On Mon 25-09-17 19:15:33, Roman Gushchin wrote: > > > > > [...] > > > > > > 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. > > > > > > 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. > > > > 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.
[toc] | [next] | [standalone]
| From | Tim Hockin <thockin@hockin.org> |
|---|---|
| Date | 2017-09-27 05:40 +0200 |
| Message-ID | <uubmx-5iR-7@gated-at.bofh.it> |
| In reply to | #1740047 |
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. On Tue, Sep 26, 2017 at 10:26 AM, Johannes Weiner <hannes@cmpxchg.org> wrote: > On Tue, Sep 26, 2017 at 03:30:40PM +0200, Michal Hocko wrote: >> On Tue 26-09-17 13:13:00, Roman Gushchin wrote: >> > On Tue, Sep 26, 2017 at 01:21:34PM +0200, Michal Hocko wrote: >> > > On Tue 26-09-17 11:59:25, Roman Gushchin wrote: >> > > > On Mon, Sep 25, 2017 at 10:25:21PM +0200, Michal Hocko wrote: >> > > > > On Mon 25-09-17 19:15:33, Roman Gushchin wrote: >> > > > > [...] >> > > > > > 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. >> > > >> > > 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. >> > >> > 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. That last sentence: > 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.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-09-27 09:50 +0200 |
| Message-ID | <uufgt-7Sm-5@gated-at.bofh.it> |
| In reply to | #1740371 |
On Tue 26-09-17 20:37:37, Tim Hockin wrote: [...] > 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. > 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. -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Tim Hockin <thockin@hockin.org> |
|---|---|
| Date | 2017-09-27 17:40 +0200 |
| Message-ID | <uumBj-4YL-17@gated-at.bofh.it> |
| In reply to | #1740473 |
On Wed, Sep 27, 2017 at 12:43 AM, Michal Hocko <mhocko@kernel.org> wrote: > On Tue 26-09-17 20:37:37, Tim Hockin wrote: > [...] >> 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. > >> 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. 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
[toc] | [prev] | [next] | [standalone]
| From | Tim Hockin <thockin@hockin.org> |
|---|---|
| Date | 2017-09-27 20:20 +0200 |
| Message-ID | <uup69-6B0-11@gated-at.bofh.it> |
| In reply to | #1740840 |
On Wed, Sep 27, 2017 at 9:23 AM, Roman Gushchin <guro@fb.com> wrote: > On Wed, Sep 27, 2017 at 08:35:50AM -0700, Tim Hockin wrote: >> On Wed, Sep 27, 2017 at 12:43 AM, Michal Hocko <mhocko@kernel.org> wrote: >> > On Tue 26-09-17 20:37:37, Tim Hockin wrote: >> > [...] >> >> 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. >> > >> >> 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. >> > > Hi, Tim! > >> 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. > >> >> 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. > > 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! 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.
[toc] | [prev] | [next] | [standalone]
| From | Shakeel Butt <shakeelb@google.com> |
|---|---|
| Date | 2017-10-02 01:30 +0200 |
| Message-ID | <uvVQl-8jo-1@gated-at.bofh.it> |
| In reply to | #1740937 |
>
> 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?
>
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 C
A 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);
[toc] | [prev] | [next] | [standalone]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2017-10-02 14:00 +0200 |
| Message-ID | <uw7y9-6Pz-5@gated-at.bofh.it> |
| In reply to | #1742910 |
Shakeel Butt wrote: > 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.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-10-02 14:30 +0200 |
| Message-ID | <uw81b-7ep-11@gated-at.bofh.it> |
| In reply to | #1742910 |
On Sun 01-10-17 16:29:48, Shakeel Butt wrote: > > > > 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? > > > > 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. -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Shakeel Butt <shakeelb@google.com> |
|---|---|
| Date | 2017-10-02 22:50 +0200 |
| Message-ID | <uwfPf-ur-225@gated-at.bofh.it> |
| In reply to | #1743173 |
> 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'.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web