From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:10
Hi,
this is version 3 of the patches to add socket memory accounting to
the unified hierarchy memory controller. Changes since v2 include:
- Fixed an underflow bug in the mem+swap counter that came through the
design of the per-cpu charge cache. To fix that, the unused mem+swap
counter is now fully patched out on unified hierarchy. Double whammy.
- Restored the counting jump label such that the networking callbacks
get patched out again when the last memory-controlled cgroup goes
away. The code was already there, so we might as well keep it.
- Broke down the massive tcp_memcontrol rewrite patch into smaller
logical pieces to (hopefully) make it easier to review and verify.
---
Socket buffer memory can make up a significant share of a workload's
memory footprint that can be directly linked to userspace activity,
and so it needs to be part of the memory controller to provide proper
resource isolation/containment.
Historically, socket buffers were accounted in a separate counter,
without any pressure equalization between anonymous memory, page
cache, and the socket buffers. When the socket buffer pool was
exhausted, buffer allocations would fail hard and cause network
performance to tank, regardless of whether there was still memory
available to the group or not. Likewise, struggling anonymous or cache
workingsets could not dip into an idle socket memory pool. Because of
this, the feature was not usable for many real life applications.
To not repeat this mistake, the new memory controller will account all
types of memory pages it is tracking on behalf of a cgroup in a single
pool. Upon pressure, the VM reclaims and shrinks and puts pressure on
whatever memory consumer in that pool is within its reach.
For socket memory, pressure feedback is provided through vmpressure
events. When the VM has trouble freeing memory, the network code is
instructed to stop growing the cgroup's transmit windows.
This series begins with a rework of the existing tcp memory controller
that simplifies and cleans up the code while allowing us to have only
one set of networking hooks for both memory controller versions. The
original behavior of the existing tcp controller should be preserved.
It then adds socket accounting to the v2 memory controller, including
the use of the per-cpu charge cache and async memory.high enforcement
from socket memory charges.
Lastly, vmpressure is hooked up to the socket code so that it stops
growing transmit windows when the VM has trouble reclaiming memory.
include/linux/memcontrol.h | 71 ++++++----
include/net/sock.h | 149 ++------------------
include/net/tcp.h | 5 +-
include/net/tcp_memcontrol.h | 1 -
mm/backing-dev.c | 2 +-
mm/memcontrol.c | 303 +++++++++++++++++++++++++++--------------
mm/vmpressure.c | 25 +++-
mm/vmscan.c | 31 +++--
net/core/sock.c | 78 +++--------
net/ipv4/tcp.c | 3 +-
net/ipv4/tcp_ipv4.c | 9 +-
net/ipv4/tcp_memcontrol.c | 85 ++++--------
net/ipv4/tcp_output.c | 7 +-
net/ipv6/tcp_ipv6.c | 3 -
14 files changed, 353 insertions(+), 419 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:06
A later patch will need this symbol in files other than memcontrol.c,
so export it now and replace mem_cgroup_root_css at the same time.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
---
include/linux/memcontrol.h | 3 ++-
mm/backing-dev.c | 2 +-
mm/memcontrol.c | 5 ++---
3 files changed, 5 insertions(+), 5 deletions(-)
@@ -275,7 +275,8 @@ struct mem_cgroup {structmem_cgroup_per_node*nodeinfo[0];/* WARNING: nodeinfo must be the last member here */};-externstructcgroup_subsys_state*mem_cgroup_root_css;++externstructmem_cgroup*root_mem_cgroup;/***mem_cgroup_events-countmemoryeventsagainstacgroup
@@ -76,9 +76,9 @@structcgroup_subsysmemory_cgrp_subsys__read_mostly;EXPORT_SYMBOL(memory_cgrp_subsys);+structmem_cgroup*root_mem_cgroup__read_mostly;+#define MEM_CGROUP_RECLAIM_RETRIES 5-staticstructmem_cgroup*root_mem_cgroup__read_mostly;-structcgroup_subsys_state*mem_cgroup_root_css__read_mostly;/* Whether the swap controller is active */#ifdef CONFIG_MEMCG_SWAP
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:14
When charging socket memory, the code currently checks only the local
page counter for excess to determine whether the memcg is under socket
pressure. But even if the local counter is fine, one of the ancestors
could have breached its limit, which should also force this child to
enter socket pressure. This currently doesn't happen.
Fix this by using page_counter_try_charge() first. If that fails, it
means that either the local counter or one of the ancestors are in
excess of their limit, and the child should enter socket pressure.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/net/sock.h | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:20
Move the jump-label from sock_update_memcg() and sock_release_memcg()
to the callsite, and so eliminate those function calls when socket
accounting is not enabled.
This also eliminates the need for dummy functions because the calls
will be optimized away if the Kconfig options are not enabled.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 9 +-------
mm/memcontrol.c | 56 +++++++++++++++++++++-------------------------
net/core/sock.c | 9 ++------
net/ipv4/tcp.c | 3 ++-
net/ipv4/tcp_ipv4.c | 4 +++-
5 files changed, 33 insertions(+), 48 deletions(-)
@@ -293,46 +293,40 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)voidsock_update_memcg(structsock*sk){-if(mem_cgroup_sockets_enabled){-structmem_cgroup*memcg;-structcg_proto*cg_proto;+structmem_cgroup*memcg;+structcg_proto*cg_proto;-BUG_ON(!sk->sk_prot->proto_cgroup);+BUG_ON(!sk->sk_prot->proto_cgroup);-/* Socket cloning can throw us here with sk_cgrp already-*filled.Itwon'thowever,necessarilyhappenfrom-*processcontext.Sothetestforrootmemcggiven-*thecurrenttask'smemcgwon'thelpusinthiscase.-*-*Respectingtheoriginalsocket'smemcgisabetter-*decisioninthiscase.-*/-if(sk->sk_cgrp){-BUG_ON(mem_cgroup_is_root(sk->sk_cgrp->memcg));-css_get(&sk->sk_cgrp->memcg->css);-return;-}+/* Socket cloning can throw us here with sk_cgrp already+*filled.Itwon'thowever,necessarilyhappenfrom+*processcontext.Sothetestforrootmemcggiven+*thecurrenttask'smemcgwon'thelpusinthiscase.+*+*Respectingtheoriginalsocket'smemcgisabetter+*decisioninthiscase.+*/+if(sk->sk_cgrp){+BUG_ON(mem_cgroup_is_root(sk->sk_cgrp->memcg));+css_get(&sk->sk_cgrp->memcg->css);+return;+}-rcu_read_lock();-memcg=mem_cgroup_from_task(current);-cg_proto=sk->sk_prot->proto_cgroup(memcg);-if(cg_proto&&test_bit(MEMCG_SOCK_ACTIVE,&cg_proto->flags)&&-css_tryget_online(&memcg->css)){-sk->sk_cgrp=cg_proto;-}-rcu_read_unlock();+rcu_read_lock();+memcg=mem_cgroup_from_task(current);+cg_proto=sk->sk_prot->proto_cgroup(memcg);+if(cg_proto&&test_bit(MEMCG_SOCK_ACTIVE,&cg_proto->flags)&&+css_tryget_online(&memcg->css)){+sk->sk_cgrp=cg_proto;}+rcu_read_unlock();}EXPORT_SYMBOL(sock_update_memcg);voidsock_release_memcg(structsock*sk){-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp){-structmem_cgroup*memcg;-WARN_ON(!sk->sk_cgrp->memcg);-memcg=sk->sk_cgrp->memcg;-css_put(&sk->sk_cgrp->memcg->css);-}+WARN_ON(!sk->sk_cgrp->memcg);+css_put(&sk->sk_cgrp->memcg->css);}structcg_proto*tcp_proto_cgroup(structmem_cgroup*memcg)
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:25
tcp_memcontrol replicates the global sysctl_mem limit array per
cgroup, but it only ever sets these entries to the value of the
memory_allocated page_counter limit. Use the latter directly.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 1 -
include/net/sock.h | 8 +++++---
net/ipv4/tcp_memcontrol.c | 8 --------
3 files changed, 5 insertions(+), 12 deletions(-)
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:33
The unified hierarchy memory controller is going to use this jump
label as well to control the networking callbacks. Move it to the
memory controller code and give it a more generic name.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 4 ++++
include/net/sock.h | 7 -------
mm/memcontrol.c | 3 +++
net/core/sock.c | 5 -----
net/ipv4/tcp_memcontrol.c | 4 ++--
5 files changed, 9 insertions(+), 14 deletions(-)
@@ -73,7 +73,7 @@ static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)*/if(!test_and_set_bit(MEMCG_SOCK_ACTIVATED,&memcg->tcp_mem.flags))-static_key_slow_inc(&memcg_socket_limit_enabled);+static_key_slow_inc(&memcg_sockets_enabled_key);set_bit(MEMCG_SOCK_ACTIVE,&memcg->tcp_mem.flags);}
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -292,8 +292,8 @@ extern int tcp_memory_pressure;/* optimized version of sk_under_memory_pressure() for TCP sockets */staticinlinebooltcp_under_memory_pressure(conststructsock*sk){-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&-mem_cgroup_under_socket_pressure(sk->sk_cgrp))+if(mem_cgroup_sockets_enabled&&sk->sk_memcg&&+mem_cgroup_under_socket_pressure(sk->sk_memcg))returntrue;returntcp_memory_pressure;
@@ -294,9 +294,6 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)voidsock_update_memcg(structsock*sk){structmem_cgroup*memcg;-structcg_proto*cg_proto;--BUG_ON(!sk->sk_prot->proto_cgroup);/* Socket cloning can throw us here with sk_cgrp already*filled.Itwon'thowever,necessarilyhappenfrom
@@ -2071,8 +2033,8 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)allocated=sk_memory_allocated_add(sk,amt);-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&-!mem_cgroup_charge_skmem(sk->sk_cgrp,amt))+if(mem_cgroup_sockets_enabled&&sk->sk_memcg&&+!mem_cgroup_charge_skmem(sk->sk_memcg,amt))gotosuppress_allocation;/* Under limit. */
@@ -2821,8 +2821,8 @@ void sk_forced_mem_schedule(struct sock *sk, int size)sk->sk_forward_alloc+=amt*SK_MEM_QUANTUM;sk_memory_allocated_add(sk,amt);-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp)-mem_cgroup_charge_skmem(sk->sk_cgrp,amt);+if(mem_cgroup_sockets_enabled&&sk->sk_memcg)+mem_cgroup_charge_skmem(sk->sk_memcg,amt);}/* Send a FIN. The caller locks the socket for us.
@@ -1869,9 +1869,6 @@ struct proto tcpv6_prot = {.compat_setsockopt=compat_tcp_setsockopt,.compat_getsockopt=compat_tcp_getsockopt,#endif-#ifdef CONFIG_MEMCG_KMEM-.proto_cgroup=tcp_proto_cgroup,-#endif.clear_sk=tcp_v6_clear_sk,};
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:40
Socket memory can be a significant share of overall memory consumed by
common workloads. In order to provide reasonable resource isolation in
the unified hierarchy, this type of memory needs to be included in the
tracking/accounting of a cgroup under active memory resource control.
Overhead is only incurred when a non-root control group is created AND
the memory controller is instructed to track and account the memory
footprint of that group. cgroup.memory=nosocket can be specified on
the boot commandline to override any runtime configuration and
forcibly exclude socket memory from active memory resource control.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 12 ++++-
mm/memcontrol.c | 131 +++++++++++++++++++++++++++++++++++++--------
2 files changed, 118 insertions(+), 25 deletions(-)
@@ -256,6 +256,10 @@ struct mem_cgroup {structwb_domaincgwb_domain;#endif+#ifdef CONFIG_INET+structwork_structsocket_work;+#endif+/* List of events which userspace want to receive */structlist_headevent_list;spinlock_tevent_list_lock;
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:42:43
Let the networking stack know when a memcg is under reclaim pressure
so that it can clamp its transmit windows accordingly.
Whenever the reclaim efficiency of a cgroup's LRU lists drops low
enough for a MEDIUM or HIGH vmpressure event to occur, assert a
pressure state in the socket and tcp memory code that tells it to curb
consumption growth from sockets associated with said control group.
vmpressure events are naturally edge triggered, so for hysteresis
assert socket pressure for a second to allow for subsequent vmpressure
events to occur before letting the socket code return to normal.
This will likely need finetuning for a wider variety of workloads, but
for now stick to the vmpressure presets and keep hysteresis simple.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 29 +++++++++++++++++++++++++----
mm/memcontrol.c | 15 +--------------
mm/vmpressure.c | 25 ++++++++++++++++++++-----
3 files changed, 46 insertions(+), 23 deletions(-)
@@ -258,6 +258,7 @@ struct mem_cgroup {#ifdef CONFIG_INETstructwork_structsocket_work;+unsignedlongsocket_pressure;#endif/* List of events which userspace want to receive */
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -294,80 +294,6 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)returnmem_cgroup_from_css(css);}-/* Writing them here to avoid exposing memcg's inner layout */-#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM)--structstatic_keymemcg_sockets_enabled_key;-EXPORT_SYMBOL(memcg_sockets_enabled_key);--voidsock_update_memcg(structsock*sk)-{-structmem_cgroup*memcg;--/* Socket cloning can throw us here with sk_cgrp already-*filled.Itwon'thowever,necessarilyhappenfrom-*processcontext.Sothetestforrootmemcggiven-*thecurrenttask'smemcgwon'thelpusinthiscase.-*-*Respectingtheoriginalsocket'smemcgisabetter-*decisioninthiscase.-*/-if(sk->sk_memcg){-BUG_ON(mem_cgroup_is_root(sk->sk_memcg));-css_get(&sk->sk_memcg->css);-return;-}--rcu_read_lock();-memcg=mem_cgroup_from_task(current);-if(memcg!=root_mem_cgroup&&-test_bit(MEMCG_SOCK_ACTIVE,&memcg->tcp_mem.flags)&&-css_tryget_online(&memcg->css))-sk->sk_memcg=memcg;-rcu_read_unlock();-}-EXPORT_SYMBOL(sock_update_memcg);--voidsock_release_memcg(structsock*sk)-{-WARN_ON(!sk->sk_memcg);-css_put(&sk->sk_memcg->css);-}--/**-*mem_cgroup_charge_skmem-chargesocketmemory-*@memcg:memcgtocharge-*@nr_pages:numberofpagestocharge-*-*Charges@nr_pagesto@memcg.Returns%trueifthechargefitwithin-*@memcg'sconfiguredlimit,%falseifthechargehadtobeforced.-*/-boolmem_cgroup_charge_skmem(structmem_cgroup*memcg,unsignedintnr_pages)-{-structpage_counter*counter;--if(page_counter_try_charge(&memcg->tcp_mem.memory_allocated,-nr_pages,&counter)){-memcg->tcp_mem.memory_pressure=0;-returntrue;-}-page_counter_charge(&memcg->tcp_mem.memory_allocated,nr_pages);-memcg->tcp_mem.memory_pressure=1;-returnfalse;-}--/**-*mem_cgroup_uncharge_skmem-unchargesocketmemory-*@memcg-memcgtouncharge-*@nr_pages-numberofpagestouncharge-*/-voidmem_cgroup_uncharge_skmem(structmem_cgroup*memcg,unsignedintnr_pages)-{-page_counter_uncharge(&memcg->tcp_mem.memory_allocated,nr_pages);-}--#endif-#ifdef CONFIG_MEMCG_KMEM/**Thiswillbethememcg'sindexineachcache's->memcg_params.memcg_caches.
@@ -5538,6 +5464,80 @@ void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage)commit_charge(newpage,memcg,true);}+/* Writing them here to avoid exposing memcg's inner layout */+#if defined(CONFIG_INET) && defined(CONFIG_MEMCG_KMEM)++structstatic_keymemcg_sockets_enabled_key;+EXPORT_SYMBOL(memcg_sockets_enabled_key);++voidsock_update_memcg(structsock*sk)+{+structmem_cgroup*memcg;++/* Socket cloning can throw us here with sk_cgrp already+*filled.Itwon'thowever,necessarilyhappenfrom+*processcontext.Sothetestforrootmemcggiven+*thecurrenttask'smemcgwon'thelpusinthiscase.+*+*Respectingtheoriginalsocket'smemcgisabetter+*decisioninthiscase.+*/+if(sk->sk_memcg){+BUG_ON(mem_cgroup_is_root(sk->sk_memcg));+css_get(&sk->sk_memcg->css);+return;+}++rcu_read_lock();+memcg=mem_cgroup_from_task(current);+if(memcg!=root_mem_cgroup&&+test_bit(MEMCG_SOCK_ACTIVE,&memcg->tcp_mem.flags)&&+css_tryget_online(&memcg->css))+sk->sk_memcg=memcg;+rcu_read_unlock();+}+EXPORT_SYMBOL(sock_update_memcg);++voidsock_release_memcg(structsock*sk)+{+WARN_ON(!sk->sk_memcg);+css_put(&sk->sk_memcg->css);+}++/**+*mem_cgroup_charge_skmem-chargesocketmemory+*@memcg:memcgtocharge+*@nr_pages:numberofpagestocharge+*+*Charges@nr_pagesto@memcg.Returns%trueifthechargefitwithin+*@memcg'sconfiguredlimit,%falseifthechargehadtobeforced.+*/+boolmem_cgroup_charge_skmem(structmem_cgroup*memcg,unsignedintnr_pages)+{+structpage_counter*counter;++if(page_counter_try_charge(&memcg->tcp_mem.memory_allocated,+nr_pages,&counter)){+memcg->tcp_mem.memory_pressure=0;+returntrue;+}+page_counter_charge(&memcg->tcp_mem.memory_allocated,nr_pages);+memcg->tcp_mem.memory_pressure=1;+returnfalse;+}++/**+*mem_cgroup_uncharge_skmem-unchargesocketmemory+*@memcg-memcgtouncharge+*@nr_pages-numberofpagestouncharge+*/+voidmem_cgroup_uncharge_skmem(structmem_cgroup*memcg,unsignedintnr_pages)+{+page_counter_uncharge(&memcg->tcp_mem.memory_allocated,nr_pages);+}++#endif+/**subsys_initcall()formemorycontroller.*
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:44:38
The unified hierarchy memory controller doesn't expose the memory+swap
counter to userspace, but its accounting is hardcoded in all charge
paths right now, including the per-cpu charge cache ("the stock").
To avoid adding yet more pointless memory+swap accounting with the
socket memory support in unified hierarchy, disable the counter
altogether when in unified hierarchy mode.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/memcontrol.c | 44 +++++++++++++++++++++++++-------------------
1 file changed, 25 insertions(+), 19 deletions(-)
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:45:01
There won't be a tcp control soft limit, so integrating the memcg code
into the global skmem limiting scheme complicates things
unnecessarily. Replace this with simple and clear charge and uncharge
calls--hidden behind a jump label--to account skb memory.
Note that this is not purely aesthetic: as a result of shoehorning the
per-memcg code into the same memory accounting functions that handle
the global level, the old code would compare the per-memcg consumption
against the smaller of the per-memcg limit and the global limit. This
allowed the total consumption of multiple sockets to exceed the global
limit, as long as the individual sockets stayed within bounds. After
this change, the code will always compare the per-memcg consumption to
the per-memcg limit, and the global consumption to the global limit,
and thus close this loophole.
Without a soft limit, the per-memcg memory pressure state in sockets
is generally questionable. However, we did it until now, so we
continue to enter it when the hard limit is hit, and packets are
dropped, to let other sockets in the cgroup know that they shouldn't
grow their transmit windows, either. However, keep it simple in the
new callback model and leave memory pressure lazily when the next
packet is accepted (as opposed to doing it synchroneously when packets
are processed). When packets are dropped, network performance will
already be in the toilet, so that should be a reasonable trade-off.
As described above, consumption is now checked on the per-memcg level
and the global level separately. Likewise, memory pressure states are
maintained on both the per-memcg level and the global level, and a
socket is considered under pressure when either level asserts as much.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 12 ++++-----
include/net/sock.h | 63 ++++++----------------------------------------
include/net/tcp.h | 5 ++--
mm/memcontrol.c | 32 +++++++++++++++++++++++
net/core/sock.c | 26 +++++++++++--------
net/ipv4/tcp_output.c | 7 ++++--
6 files changed, 69 insertions(+), 76 deletions(-)
@@ -292,8 +292,9 @@ extern int tcp_memory_pressure;/* optimized version of sk_under_memory_pressure() for TCP sockets */staticinlinebooltcp_under_memory_pressure(conststructsock*sk){-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp)-return!!sk->sk_cgrp->memory_pressure;+if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&+mem_cgroup_under_socket_pressure(sk->sk_cgrp))+returntrue;returntcp_memory_pressure;}
@@ -2066,27 +2066,27 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)structproto*prot=sk->sk_prot;intamt=sk_mem_pages(size);longallocated;-intparent_status=UNDER_LIMIT;sk->sk_forward_alloc+=amt*SK_MEM_QUANTUM;-allocated=sk_memory_allocated_add(sk,amt,&parent_status);+allocated=sk_memory_allocated_add(sk,amt);++if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&+!mem_cgroup_charge_skmem(sk->sk_cgrp,amt))+gotosuppress_allocation;/* Under limit. */-if(parent_status==UNDER_LIMIT&&-allocated<=sk_prot_mem_limits(sk,0)){+if(allocated<=sk_prot_mem_limits(sk,0)){sk_leave_memory_pressure(sk);return1;}-/* Under pressure. (we or our parents) */-if((parent_status>SOFT_LIMIT)||-allocated>sk_prot_mem_limits(sk,1))+/* Under pressure. */+if(allocated>sk_prot_mem_limits(sk,1))sk_enter_memory_pressure(sk);-/* Over hard limit (we or our parents) */-if((parent_status==OVER_LIMIT)||-(allocated>sk_prot_mem_limits(sk,2)))+/* Over hard limit. */+if(allocated>sk_prot_mem_limits(sk,2))gotosuppress_allocation;/* guarantee minimum buffer size under pressure */
@@ -2813,13 +2813,16 @@ begin_fwd:*/voidsk_forced_mem_schedule(structsock*sk,intsize){-intamt,status;+intamt;if(size<=sk->sk_forward_alloc)return;amt=sk_mem_pages(size);sk->sk_forward_alloc+=amt*SK_MEM_QUANTUM;-sk_memory_allocated_add(sk,amt,&status);+sk_memory_allocated_add(sk,amt);++if(mem_cgroup_sockets_enabled&&sk->sk_cgrp)+mem_cgroup_charge_skmem(sk->sk_cgrp,amt);}/* Send a FIN. The caller locks the socket for us.
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:45:57
The number of allocated sockets is used for calculations in the soft
limit phase, where packets are accepted but the socket is under memory
pressure. Since there is no soft limit phase in tcp_memcontrol, and
memory pressure is only entered when packets are already dropped, this
is actually dead code. Remove it.
As this is the last user of parent_cg_proto(), remove that too.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 1 -
include/net/sock.h | 39 +++------------------------------------
net/ipv4/tcp_memcontrol.c | 3 ---
3 files changed, 3 insertions(+), 40 deletions(-)
@@ -97,7 +97,6 @@ enum cg_proto_flags {structcg_proto{structpage_countermemory_allocated;/* Current allocated memory. */-structpercpu_countersockets_allocated;/* Current number of sockets. */intmemory_pressure;longsysctl_mem[3];unsignedlongflags;
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:46:45
When a cgroup currently breaches its socket memory limit, it enters
memory pressure mode for itself and its *ancestors*. This throttles
transmission in unrelated sibling and cousin subtrees that have
nothing to do with the breached limit.
On the contrary, breaching a limit should make that group and its
*children* enter memory pressure mode. But this happens already,
albeit lazily: if an ancestor limit is breached, siblings will enter
memory pressure on their own once the next packet arrives for them.
So no additional hierarchy code is needed. Remove the bogus stuff.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/net/sock.h | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-12 23:47:33
Letting shrink_slab() handle the root_mem_cgroup, and implicitely the
!CONFIG_MEMCG case, allows shrink_zone() to invoke the shrinkers
unconditionally from within the memcg iteration loop.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
---
include/linux/memcontrol.h | 2 ++
mm/vmscan.c | 31 ++++++++++++++++---------------
2 files changed, 18 insertions(+), 15 deletions(-)
@@ -411,6 +411,10 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid,structshrinker*shrinker;unsignedlongfreed=0;+/* Global shrinker mode */+if(memcg==root_mem_cgroup)+memcg=NULL;+if(memcg&&!memcg_kmem_is_active(memcg))return0;
--
2.6.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This looks wrong ?
if (A && B && C)
return !!*sk->sk_prot->memory_pressure;
<compiler should eventually barf,
as this function should not return void>
}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This looks wrong ?
if (A && B && C)
return !!*sk->sk_prot->memory_pressure;
<compiler should eventually barf,
as this function should not return void>
Yikes, you're right. This is missing a return true.
[ Just forced a complete rebuild and of course it warns at control
reaching end of non-void function. ]
I'm stumped by how I could have missed it as I rebuild after every
commit with make -s, so a warning should stand out. And it should
definitely rebuild the callers frequently as most patches change
memcontrol.h. Probably a screwup in the final series polishing.
I'm going to go over this carefully one more time tomorrow.
Meanwhile, this is the missing piece and the updated patch.
Thanks Eric.
From 4a24ca67e5b0f651a68807ee99f714437ffd6109 Mon Sep 17 00:00:00 2001
From: Johannes Weiner <redacted>
Date: Tue, 10 Nov 2015 17:14:41 -0500
Subject: [PATCH v2] net: tcp_memcontrol: sanitize tcp memory accounting callbacks
There won't be a tcp control soft limit, so integrating the memcg code
into the global skmem limiting scheme complicates things
unnecessarily. Replace this with simple and clear charge and uncharge
calls--hidden behind a jump label--to account skb memory.
Note that this is not purely aesthetic: as a result of shoehorning the
per-memcg code into the same memory accounting functions that handle
the global level, the old code would compare the per-memcg consumption
against the smaller of the per-memcg limit and the global limit. This
allowed the total consumption of multiple sockets to exceed the global
limit, as long as the individual sockets stayed within bounds. After
this change, the code will always compare the per-memcg consumption to
the per-memcg limit, and the global consumption to the global limit,
and thus close this loophole.
Without a soft limit, the per-memcg memory pressure state in sockets
is generally questionable. However, we did it until now, so we
continue to enter it when the hard limit is hit, and packets are
dropped, to let other sockets in the cgroup know that they shouldn't
grow their transmit windows, either. However, keep it simple in the
new callback model and leave memory pressure lazily when the next
packet is accepted (as opposed to doing it synchroneously when packets
are processed). When packets are dropped, network performance will
already be in the toilet, so that should be a reasonable trade-off.
As described above, consumption is now checked on the per-memcg level
and the global level separately. Likewise, memory pressure states are
maintained on both the per-memcg level and the global level, and a
socket is considered under pressure when either level asserts as much.
Signed-off-by: Johannes Weiner <redacted>
---
include/linux/memcontrol.h | 12 ++++-----
include/net/sock.h | 64 ++++++----------------------------------------
include/net/tcp.h | 5 ++--
mm/memcontrol.c | 32 +++++++++++++++++++++++
net/core/sock.c | 26 +++++++++++--------
net/ipv4/tcp_output.c | 7 +++--
6 files changed, 70 insertions(+), 76 deletions(-)
@@ -292,8 +292,9 @@ extern int tcp_memory_pressure;/* optimized version of sk_under_memory_pressure() for TCP sockets */staticinlinebooltcp_under_memory_pressure(conststructsock*sk){-if(mem_cgroup_sockets_enabled&&sk->sk_cgrp)-return!!sk->sk_cgrp->memory_pressure;+if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&+mem_cgroup_under_socket_pressure(sk->sk_cgrp))+returntrue;returntcp_memory_pressure;}
@@ -2066,27 +2066,27 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)structproto*prot=sk->sk_prot;intamt=sk_mem_pages(size);longallocated;-intparent_status=UNDER_LIMIT;sk->sk_forward_alloc+=amt*SK_MEM_QUANTUM;-allocated=sk_memory_allocated_add(sk,amt,&parent_status);+allocated=sk_memory_allocated_add(sk,amt);++if(mem_cgroup_sockets_enabled&&sk->sk_cgrp&&+!mem_cgroup_charge_skmem(sk->sk_cgrp,amt))+gotosuppress_allocation;/* Under limit. */-if(parent_status==UNDER_LIMIT&&-allocated<=sk_prot_mem_limits(sk,0)){+if(allocated<=sk_prot_mem_limits(sk,0)){sk_leave_memory_pressure(sk);return1;}-/* Under pressure. (we or our parents) */-if((parent_status>SOFT_LIMIT)||-allocated>sk_prot_mem_limits(sk,1))+/* Under pressure. */+if(allocated>sk_prot_mem_limits(sk,1))sk_enter_memory_pressure(sk);-/* Over hard limit (we or our parents) */-if((parent_status==OVER_LIMIT)||-(allocated>sk_prot_mem_limits(sk,2)))+/* Over hard limit. */+if(allocated>sk_prot_mem_limits(sk,2))gotosuppress_allocation;/* guarantee minimum buffer size under pressure */
@@ -2813,13 +2813,16 @@ begin_fwd:*/voidsk_forced_mem_schedule(structsock*sk,intsize){-intamt,status;+intamt;if(size<=sk->sk_forward_alloc)return;amt=sk_mem_pages(size);sk->sk_forward_alloc+=amt*SK_MEM_QUANTUM;-sk_memory_allocated_add(sk,amt,&status);+sk_memory_allocated_add(sk,amt);++if(mem_cgroup_sockets_enabled&&sk->sk_cgrp)+mem_cgroup_charge_skmem(sk->sk_cgrp,amt);}/* Send a FIN. The caller locks the socket for us.
From: Michal Hocko <mhocko@kernel.org> Date: 2015-11-13 10:37:57
On Thu 12-11-15 18:41:30, Johannes Weiner wrote:
The unified hierarchy memory controller doesn't expose the memory+swap
counter to userspace, but its accounting is hardcoded in all charge
paths right now, including the per-cpu charge cache ("the stock").
To avoid adding yet more pointless memory+swap accounting with the
socket memory support in unified hierarchy, disable the counter
altogether when in unified hierarchy mode.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Michal Hocko <mhocko@kernel.org> Date: 2015-11-13 10:43:17
On Thu 12-11-15 18:41:29, Johannes Weiner wrote:
The unified hierarchy memory controller is going to use this jump
label as well to control the networking callbacks. Move it to the
memory controller code and give it a more generic name.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Yes it makes more sense in memcg proper
Acked-by: Michal Hocko <mhocko@suse.com>
@@ -73,7 +73,7 @@ static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)*/if(!test_and_set_bit(MEMCG_SOCK_ACTIVATED,&memcg->tcp_mem.flags))-static_key_slow_inc(&memcg_socket_limit_enabled);+static_key_slow_inc(&memcg_sockets_enabled_key);set_bit(MEMCG_SOCK_ACTIVE,&memcg->tcp_mem.flags);}
--
2.6.2
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 15:59:37
From: Johannes Weiner <redacted>
Date: Thu, 12 Nov 2015 18:41:20 -0500
A later patch will need this symbol in files other than memcontrol.c,
so export it now and replace mem_cgroup_root_css at the same time.
Signed-off-by: Johannes Weiner <redacted>
Acked-by: Michal Hocko <mhocko-IBi9RG/b67k@public.gmane.org>
Acked-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 15:59:52
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Thu, 12 Nov 2015 18:41:21 -0500
Letting shrink_slab() handle the root_mem_cgroup, and implicitely the
!CONFIG_MEMCG case, allows shrink_zone() to invoke the shrinkers
unconditionally from within the memcg iteration loop.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: David S. Miller <davem@davemloft.net>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 16:00:19
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Thu, 12 Nov 2015 18:41:22 -0500
When charging socket memory, the code currently checks only the local
page counter for excess to determine whether the memcg is under socket
pressure. But even if the local counter is fine, one of the ancestors
could have breached its limit, which should also force this child to
enter socket pressure. This currently doesn't happen.
Fix this by using page_counter_try_charge() first. If that fails, it
means that either the local counter or one of the ancestors are in
excess of their limit, and the child should enter socket pressure.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: David S. Miller <davem@davemloft.net>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 16:00:32
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Thu, 12 Nov 2015 18:41:23 -0500
When a cgroup currently breaches its socket memory limit, it enters
memory pressure mode for itself and its *ancestors*. This throttles
transmission in unrelated sibling and cousin subtrees that have
nothing to do with the breached limit.
On the contrary, breaching a limit should make that group and its
*children* enter memory pressure mode. But this happens already,
albeit lazily: if an ancestor limit is breached, siblings will enter
memory pressure on their own once the next packet arrives for them.
So no additional hierarchy code is needed. Remove the bogus stuff.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 16:01:26
From: Johannes Weiner <redacted>
Date: Thu, 12 Nov 2015 18:41:24 -0500
Move the jump-label from sock_update_memcg() and sock_release_memcg()
to the callsite, and so eliminate those function calls when socket
accounting is not enabled.
This also eliminates the need for dummy functions because the calls
will be optimized away if the Kconfig options are not enabled.
Signed-off-by: Johannes Weiner <redacted>
Acked-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
From: David Miller <davem@davemloft.net> Date: 2015-11-13 16:01:41
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Thu, 12 Nov 2015 18:41:25 -0500
The number of allocated sockets is used for calculations in the soft
limit phase, where packets are accepted but the socket is under memory
pressure. Since there is no soft limit phase in tcp_memcontrol, and
memory pressure is only entered when packets are already dropped, this
is actually dead code. Remove it.
As this is the last user of parent_cg_proto(), remove that too.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: David S. Miller <davem@davemloft.net>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-14 12:17:59
On Thu, Nov 12, 2015 at 06:41:20PM -0500, Johannes Weiner wrote:
A later patch will need this symbol in files other than memcontrol.c,
so export it now and replace mem_cgroup_root_css at the same time.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -411,6 +411,10 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid,structshrinker*shrinker;unsignedlongfreed=0;+/* Global shrinker mode */+if(memcg==root_mem_cgroup)+memcg=NULL;+if(memcg&&!memcg_kmem_is_active(memcg))return0;
AFAICS this patch deadly breaks memcg-unaware shrinkers vs LRU balance:
currently we scan (*total* LRU scanned / *total* LRU pages) of all such
objects; with this patch we'd use the numbers from the root cgroup
instead. If most processes reside in memory cgroups, the root cgroup
will have only a few LRU pages and hence the pressure exerted upon such
objects will be unfairly severe.
Thanks,
Vladimir
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-14 12:46:11
On Thu, Nov 12, 2015 at 06:41:22PM -0500, Johannes Weiner wrote:
When charging socket memory, the code currently checks only the local
page counter for excess to determine whether the memcg is under socket
pressure. But even if the local counter is fine, one of the ancestors
could have breached its limit, which should also force this child to
enter socket pressure. This currently doesn't happen.
Fix this by using page_counter_try_charge() first. If that fails, it
means that either the local counter or one of the ancestors are in
excess of their limit, and the child should enter socket pressure.
Signed-off-by: Johannes Weiner <redacted>
Reviewed-by: Vladimir Davydov <redacted>
For the record: it was broken by commit 3e32cb2e0a12 ("mm: memcontrol:
lockless page counters").
From: Vladimir Davydov <hidden> Date: 2015-11-14 13:23:44
On Thu, Nov 12, 2015 at 06:41:30PM -0500, Johannes Weiner wrote:
The unified hierarchy memory controller doesn't expose the memory+swap
counter to userspace, but its accounting is hardcoded in all charge
paths right now, including the per-cpu charge cache ("the stock").
To avoid adding yet more pointless memory+swap accounting with the
socket memory support in unified hierarchy, disable the counter
altogether when in unified hierarchy mode.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-14 13:30:01
On Thu, Nov 12, 2015 at 06:41:29PM -0500, Johannes Weiner wrote:
The unified hierarchy memory controller is going to use this jump
label as well to control the networking callbacks. Move it to the
memory controller code and give it a more generic name.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-14 15:06:25
On Sat, Nov 14, 2015 at 03:36:50PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:21PM -0500, Johannes Weiner wrote:
quoted
@@ -2432,20 +2447,6 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc, } } while ((memcg = mem_cgroup_iter(root, memcg, &reclaim)));- /*- * Shrink the slab caches in the same proportion that- * the eligible LRU pages were scanned.- */- if (global_reclaim(sc) && is_classzone)- shrink_slab(sc->gfp_mask, zone_to_nid(zone), NULL,- sc->nr_scanned - nr_scanned,- zone_lru_pages);-- if (reclaim_state) {- sc->nr_reclaimed += reclaim_state->reclaimed_slab;- reclaim_state->reclaimed_slab = 0;- }-
AFAICS this patch deadly breaks memcg-unaware shrinkers vs LRU balance:
currently we scan (*total* LRU scanned / *total* LRU pages) of all such
objects; with this patch we'd use the numbers from the root cgroup
instead. If most processes reside in memory cgroups, the root cgroup
will have only a few LRU pages and hence the pressure exerted upon such
objects will be unfairly severe.
You're absolutely right, good catch.
Please disregard this patch. It's not necessary for this series after
v2, I just kept it because I thought it's a nice simplification that's
possible after making root_mem_cgroup public.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-14 15:15:32
On Sat, Nov 14, 2015 at 03:45:52PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:22PM -0500, Johannes Weiner wrote:
quoted
When charging socket memory, the code currently checks only the local
page counter for excess to determine whether the memcg is under socket
pressure. But even if the local counter is fine, one of the ancestors
could have breached its limit, which should also force this child to
enter socket pressure. This currently doesn't happen.
Fix this by using page_counter_try_charge() first. If that fails, it
means that either the local counter or one of the ancestors are in
excess of their limit, and the child should enter socket pressure.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Vladimir Davydov <redacted>
Thanks Vladimir!
For the record: it was broken by commit 3e32cb2e0a12 ("mm: memcontrol:
lockless page counters").
From: Vladimir Davydov <hidden> Date: 2015-11-14 16:33:34
On Thu, Nov 12, 2015 at 06:41:24PM -0500, Johannes Weiner wrote:
Move the jump-label from sock_update_memcg() and sock_release_memcg()
to the callsite, and so eliminate those function calls when socket
accounting is not enabled.
I don't believe this patch's necessary, because these functions aren't
hot paths. Neither do I think it makes the code look better. Anyway,
it's rather a matter of personal preference, and the patch looks correct
to me, so
Reviewed-by: Vladimir Davydov <redacted>
This also eliminates the need for dummy functions because the calls
will be optimized away if the Kconfig options are not enabled.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-15 13:55:20
On Thu, Nov 12, 2015 at 06:41:33PM -0500, Johannes Weiner wrote:
Let the networking stack know when a memcg is under reclaim pressure
so that it can clamp its transmit windows accordingly.
Whenever the reclaim efficiency of a cgroup's LRU lists drops low
enough for a MEDIUM or HIGH vmpressure event to occur, assert a
pressure state in the socket and tcp memory code that tells it to curb
consumption growth from sockets associated with said control group.
vmpressure events are naturally edge triggered, so for hysteresis
assert socket pressure for a second to allow for subsequent vmpressure
events to occur before letting the socket code return to normal.
AFAICS, in contrast to v1, now you don't modify vmpressure behavior,
which means socket_pressure will only be set when cgroup hits its
high/hard limit. On tightly packed system, this is unlikely IMO -
cgroups will mostly experience pressure due to memory shortage at the
global level and/or their low limit configuration, in which case no
vmpressure events will be triggered and therefore tcp window won't be
clamped accordingly.
May be, we could use a per memcg slab shrinker to detect memory
pressure? This looks like abusing shrinkers API though.
Thanks,
Vladimir
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Michal Hocko <mhocko@kernel.org> Date: 2015-11-16 15:59:34
On Thu 12-11-15 18:41:32, Johannes Weiner wrote:
Socket memory can be a significant share of overall memory consumed by
common workloads. In order to provide reasonable resource isolation in
the unified hierarchy, this type of memory needs to be included in the
tracking/accounting of a cgroup under active memory resource control.
Overhead is only incurred when a non-root control group is created AND
the memory controller is instructed to track and account the memory
footprint of that group. cgroup.memory=nosocket can be specified on
the boot commandline to override any runtime configuration and
forcibly exclude socket memory from active memory resource control.
Do you have any numbers about the overhead?
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
With a way to disable this feature I am OK with it.
cgroup.memory=nosocket should be documented (at least in
Documentation/kernel-parameters.txt)
Other than that
Acked-by: Michal Hocko <mhocko@suse.com>
@@ -256,6 +256,10 @@ struct mem_cgroup {structwb_domaincgwb_domain;#endif+#ifdef CONFIG_INET+structwork_structsocket_work;+#endif+/* List of events which userspace want to receive */structlist_headevent_list;spinlock_tevent_list_lock;
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-16 17:52:26
On Sat, Nov 14, 2015 at 07:33:10PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:24PM -0500, Johannes Weiner wrote:
quoted
Move the jump-label from sock_update_memcg() and sock_release_memcg()
to the callsite, and so eliminate those function calls when socket
accounting is not enabled.
I don't believe this patch's necessary, because these functions aren't
hot paths. Neither do I think it makes the code look better. Anyway,
it's rather a matter of personal preference, and the patch looks correct
to me, so
Yeah, it's not a hotpath. What I like primarily about this patch I
guess is that makes it more consistent how memcg entry is gated. You
don't have to remember which functions have the checks in the caller
and which have it in the function themselves. And I really hate the
static inline void foo(void)
{
if (foo_enabled())
__foo()
}
in the headerfile pattern.
Reviewed-by: Vladimir Davydov <redacted>
Thanks, I appreciate you acking it despite your personal preference!
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-16 18:18:22
On Mon, Nov 16, 2015 at 04:59:25PM +0100, Michal Hocko wrote:
On Thu 12-11-15 18:41:32, Johannes Weiner wrote:
quoted
Socket memory can be a significant share of overall memory consumed by
common workloads. In order to provide reasonable resource isolation in
the unified hierarchy, this type of memory needs to be included in the
tracking/accounting of a cgroup under active memory resource control.
Overhead is only incurred when a non-root control group is created AND
the memory controller is instructed to track and account the memory
footprint of that group. cgroup.memory=nosocket can be specified on
the boot commandline to override any runtime configuration and
forcibly exclude socket memory from active memory resource control.
Do you have any numbers about the overhead?
Hm? Performance numbers make sense when you have a specific scenario
and a theory on how to optimize the implementation for it. What load
would you test and what would be the baseline to compare it to?
quoted
Signed-off-by: Johannes Weiner <redacted>
With a way to disable this feature I am OK with it.
cgroup.memory=nosocket should be documented (at least in
Documentation/kernel-parameters.txt)
@@ -599,6 +599,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. cut the overhead, others just disable the usage. So only cgroup_disable=memory is actually worthy}+ cgroup.memory= [KNL] Pass options to the cgroup memory controller.+ Format: <string>+ nosocket -- Disable socket memory accounting.+ checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text.
Other than that
Acked-by: Michal Hocko <mhocko-IBi9RG/b67k@public.gmane.org>
Thanks!
---
From abe0670cec1424a5b4f43dfabff8bb27a1007ced Mon Sep 17 00:00:00 2001
From: Johannes Weiner <redacted>
Date: Wed, 14 Oct 2015 22:25:20 -0700
Subject: [PATCH] mm: memcontrol: account socket memory in unified hierarchy
memory controller
Socket memory can be a significant share of overall memory consumed by
common workloads. In order to provide reasonable resource isolation in
the unified hierarchy, this type of memory needs to be included in the
tracking/accounting of a cgroup under active memory resource control.
Overhead is only incurred when a non-root control group is created AND
the memory controller is instructed to track and account the memory
footprint of that group. cgroup.memory=nosocket can be specified on
the boot commandline to override any runtime configuration and
forcibly exclude socket memory from active memory resource control.
Signed-off-by: Johannes Weiner <redacted>
Acked-by: Michal Hocko <mhocko-IBi9RG/b67k@public.gmane.org>
---
Documentation/kernel-parameters.txt | 4 ++
include/linux/memcontrol.h | 12 +++-
mm/memcontrol.c | 131 +++++++++++++++++++++++++++++-------
3 files changed, 122 insertions(+), 25 deletions(-)
@@ -599,6 +599,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. cut the overhead, others just disable the usage. So only cgroup_disable=memory is actually worthy}+ cgroup.memory= [KNL] Pass options to the cgroup memory controller.+ Format: <string>+ nosocket -- Disable socket memory accounting.+ checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text.
@@ -256,6 +256,10 @@ struct mem_cgroup {structwb_domaincgwb_domain;#endif+#ifdef CONFIG_INET+structwork_structsocket_work;+#endif+/* List of events which userspace want to receive */structlist_headevent_list;spinlock_tevent_list_lock;
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-16 18:53:31
On Sun, Nov 15, 2015 at 04:54:57PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:33PM -0500, Johannes Weiner wrote:
quoted
Let the networking stack know when a memcg is under reclaim pressure
so that it can clamp its transmit windows accordingly.
Whenever the reclaim efficiency of a cgroup's LRU lists drops low
enough for a MEDIUM or HIGH vmpressure event to occur, assert a
pressure state in the socket and tcp memory code that tells it to curb
consumption growth from sockets associated with said control group.
vmpressure events are naturally edge triggered, so for hysteresis
assert socket pressure for a second to allow for subsequent vmpressure
events to occur before letting the socket code return to normal.
AFAICS, in contrast to v1, now you don't modify vmpressure behavior,
which means socket_pressure will only be set when cgroup hits its
high/hard limit. On tightly packed system, this is unlikely IMO -
cgroups will mostly experience pressure due to memory shortage at the
global level and/or their low limit configuration, in which case no
vmpressure events will be triggered and therefore tcp window won't be
clamped accordingly.
Yeah, this is an inherent problem in the vmpressure design and it
makes the feature significantly less useful than it could be IMO.
But you guys were wary about the patch that changed it, and this
series has kicked up enough dust already, so I backed it out.
But this will still be useful. Yes, it won't help in rebalancing an
regularly working system, which would be cool, but it'll still help
contain a worklad that is growing beyond expectations, which is the
scenario that kickstarted this work.
May be, we could use a per memcg slab shrinker to detect memory
pressure? This looks like abusing shrinkers API though.
Actually, I thought about doing this long-term.
Shrinkers are a nice way to export VM pressure to auxiliary allocators
and caches. But currently, the only metric we export is LRU scan rate,
whose application is limited to ageable caches: it doesn't make sense
to cause auxiliary workingsets to shrink when the VM is merely picking
up the drop-behind pages of a one-off page cache stream. I think it
would make sense for shrinkers to include reclaim efficiency so that
they can be used by caches that don't have 'accessed' bits and object
rotation, but are able to shrink based on the cost they're imposing.
But a change like this is beyond the scope of this series, IMO.
From: Vladimir Davydov <hidden> Date: 2015-11-17 20:19:12
On Mon, Nov 16, 2015 at 01:53:16PM -0500, Johannes Weiner wrote:
On Sun, Nov 15, 2015 at 04:54:57PM +0300, Vladimir Davydov wrote:
quoted
On Thu, Nov 12, 2015 at 06:41:33PM -0500, Johannes Weiner wrote:
quoted
Let the networking stack know when a memcg is under reclaim pressure
so that it can clamp its transmit windows accordingly.
Whenever the reclaim efficiency of a cgroup's LRU lists drops low
enough for a MEDIUM or HIGH vmpressure event to occur, assert a
pressure state in the socket and tcp memory code that tells it to curb
consumption growth from sockets associated with said control group.
vmpressure events are naturally edge triggered, so for hysteresis
assert socket pressure for a second to allow for subsequent vmpressure
events to occur before letting the socket code return to normal.
AFAICS, in contrast to v1, now you don't modify vmpressure behavior,
which means socket_pressure will only be set when cgroup hits its
high/hard limit. On tightly packed system, this is unlikely IMO -
cgroups will mostly experience pressure due to memory shortage at the
global level and/or their low limit configuration, in which case no
vmpressure events will be triggered and therefore tcp window won't be
clamped accordingly.
Yeah, this is an inherent problem in the vmpressure design and it
makes the feature significantly less useful than it could be IMO.
AFAIK vmpressure was designed to allow userspace to tune hard limits of
cgroups in accordance with their demands, in which case the way how
vmpressure notifications work makes sense.
But you guys were wary about the patch that changed it, and this
Changing vmpressure semantics as you proposed in v1 would result in
userspace getting notifications even if cgroup does not hit its limit.
May be it could be useful to someone (e.g. it could help tuning
memory.low), but I am pretty sure this would also result in breakages
for others.
series has kicked up enough dust already, so I backed it out.
But this will still be useful. Yes, it won't help in rebalancing an
regularly working system, which would be cool, but it'll still help
contain a worklad that is growing beyond expectations, which is the
scenario that kickstarted this work.
I haven't looked through all the previous patches in the series, but
AFAIU they should do the trick, no? Notifying sockets about vmpressure
is rather needed to protect a workload from itself. And with this patch
it will work this way, but only if sum limits < total ram, which is
rather rare in practice. On tightly packed systems it does nothing.
That said, I don't think we should commit this particular patch. Neither
do I think socket accounting should be enabled by default in the unified
hierarchy for now, since the implementation is still incomplete. IMHO.
Thanks,
Vladimir
quoted
May be, we could use a per memcg slab shrinker to detect memory
pressure? This looks like abusing shrinkers API though.
Actually, I thought about doing this long-term.
Shrinkers are a nice way to export VM pressure to auxiliary allocators
and caches. But currently, the only metric we export is LRU scan rate,
whose application is limited to ageable caches: it doesn't make sense
to cause auxiliary workingsets to shrink when the VM is merely picking
up the drop-behind pages of a one-off page cache stream. I think it
would make sense for shrinkers to include reclaim efficiency so that
they can be used by caches that don't have 'accessed' bits and object
rotation, but are able to shrink based on the cost they're imposing.
But a change like this is beyond the scope of this series, IMO.
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-17 22:22:36
On Tue, Nov 17, 2015 at 11:18:50PM +0300, Vladimir Davydov wrote:
AFAIK vmpressure was designed to allow userspace to tune hard limits of
cgroups in accordance with their demands, in which case the way how
vmpressure notifications work makes sense.
You can still do that when the reporting happens on the reclaim level,
it's easy to figure out where the pressure comes from once a group is
struggling to reclaim its LRU pages.
Reporting on the pressure level does nothing but destroy valuable
information that would be useful in scenarios other than tuning a
hierarchical memory limit.
quoted
But you guys were wary about the patch that changed it, and this
Changing vmpressure semantics as you proposed in v1 would result in
userspace getting notifications even if cgroup does not hit its limit.
May be it could be useful to someone (e.g. it could help tuning
memory.low), but I am pretty sure this would also result in breakages
for others.
Maybe. I'll look into a two-layer vmpressure recording/reporting model
that would give us reclaim-level events internally while retaining
pressure-level events for the existing userspace interface.
quoted
series has kicked up enough dust already, so I backed it out.
But this will still be useful. Yes, it won't help in rebalancing an
regularly working system, which would be cool, but it'll still help
contain a worklad that is growing beyond expectations, which is the
scenario that kickstarted this work.
I haven't looked through all the previous patches in the series, but
AFAIU they should do the trick, no? Notifying sockets about vmpressure
is rather needed to protect a workload from itself.
No, the only critical thing is to protect the system from OOM
conditions caused by what should be containerized processes.
That's a correctness issue.
How much we mitigate the consequences inside the container when the
workload screws up is secondary. But even that is already much better
in this series compared to memcg v1, while leaving us with all the
freedom to continue improving this internal mitigation in the future.
And with this patch it will work this way, but only if sum limits <
total ram, which is rather rare in practice. On tightly packed
systems it does nothing.
That's not true, it's still useful when things go south inside a
cgroup, even with overcommitted limits. See above.
We can optimize the continuous global pressure rebalancing later on;
whether that'll be based on a modified vmpressure implementation, or
adding reclaim efficiency to the shrinker API or whatever.
That said, I don't think we should commit this particular patch. Neither
do I think socket accounting should be enabled by default in the unified
hierarchy for now, since the implementation is still incomplete. IMHO.
I don't see a technical basis for either of those suggestions.
From: Vladimir Davydov <hidden> Date: 2015-11-18 16:03:16
On Tue, Nov 17, 2015 at 05:22:17PM -0500, Johannes Weiner wrote:
On Tue, Nov 17, 2015 at 11:18:50PM +0300, Vladimir Davydov wrote:
quoted
AFAIK vmpressure was designed to allow userspace to tune hard limits of
cgroups in accordance with their demands, in which case the way how
vmpressure notifications work makes sense.
You can still do that when the reporting happens on the reclaim level,
it's easy to figure out where the pressure comes from once a group is
struggling to reclaim its LRU pages.
Right, one only needs to check usage-vs-limit in the cgroup that
received a notification and all its ascendants, but I doubt existing
applications do that.
Reporting on the pressure level does nothing but destroy valuable
information that would be useful in scenarios other than tuning a
hierarchical memory limit.
Agree.
quoted
quoted
But you guys were wary about the patch that changed it, and this
Changing vmpressure semantics as you proposed in v1 would result in
userspace getting notifications even if cgroup does not hit its limit.
May be it could be useful to someone (e.g. it could help tuning
memory.low), but I am pretty sure this would also result in breakages
for others.
Maybe. I'll look into a two-layer vmpressure recording/reporting model
that would give us reclaim-level events internally while retaining
pressure-level events for the existing userspace interface.
It would be great. I think vmpressure, as you propose to implement it,
could be useful even in the unified hierarchy for tuning memory.low and
memory.high.
quoted
quoted
series has kicked up enough dust already, so I backed it out.
But this will still be useful. Yes, it won't help in rebalancing an
regularly working system, which would be cool, but it'll still help
contain a worklad that is growing beyond expectations, which is the
scenario that kickstarted this work.
I haven't looked through all the previous patches in the series, but
AFAIU they should do the trick, no? Notifying sockets about vmpressure
is rather needed to protect a workload from itself.
No, the only critical thing is to protect the system from OOM
conditions caused by what should be containerized processes.
That's a correctness issue.
How much we mitigate the consequences inside the container when the
workload screws up is secondary. But even that is already much better
in this series compared to memcg v1, while leaving us with all the
freedom to continue improving this internal mitigation in the future.
quoted
And with this patch it will work this way, but only if sum limits <
total ram, which is rather rare in practice. On tightly packed
systems it does nothing.
That's not true, it's still useful when things go south inside a
cgroup, even with overcommitted limits. See above.
I meant solely this patch here, not the rest of the patch set. In the
overcommitted case there is no difference if we have the last patch or
not AFAIU.
We can optimize the continuous global pressure rebalancing later on;
whether that'll be based on a modified vmpressure implementation, or
adding reclaim efficiency to the shrinker API or whatever.
quoted
That said, I don't think we should commit this particular patch. Neither
do I think socket accounting should be enabled by default in the unified
hierarchy for now, since the implementation is still incomplete. IMHO.
I don't see a technical basis for either of those suggestions.
IMHO users switching to the unified hierarchy don't expect that
something gets broken in the default setup unless it's a bug. They
expect API changes, new functionality appeared, some features dropped,
but not breakages.
With this patch set, one gets socket accounting enabled by default,
which would be OK if it always worked right, at least in theory. But it
does not if the node is overcommitted - one might get unexpected local
OOMs due to growing socket buffers, which have never been seen in the
legacy hierarchy.
You say that it will help coping with global OOM, which is true, but it
looks like trading an old problem for a new one, which is unaccepted in
this particular case IMHO, because the legacy hierarchy has been used
for years and people are likely to be used to old problems such as lack
of socket buffers accounting - they might already work around this
problem by tuning global tcp limits for instance. After switching to the
unified hierarchy they'll get a new problem in the default setup, which
is no good IMHO.
I'm not against enabling socket buffers accounting by default, but only
once it is expected to work in 99% cases, at least theoretically.
Why can't we apply all patches but the last one (they look OK at first
glance, but I need more time to review them carefully) and disable
socket accounting by default for now? Then you or someone else would
prepare a separate patch set introducing vmpressure propagation to
socket code, so that socket accounting could be enabled by default.
I don't insist. It's just my vision on how things should be done.
Thanks,
Vladimir
From: Michal Hocko <mhocko@kernel.org> Date: 2015-11-18 16:23:02
On Mon 16-11-15 13:18:10, Johannes Weiner wrote:
On Mon, Nov 16, 2015 at 04:59:25PM +0100, Michal Hocko wrote:
quoted
On Thu 12-11-15 18:41:32, Johannes Weiner wrote:
quoted
Socket memory can be a significant share of overall memory consumed by
common workloads. In order to provide reasonable resource isolation in
the unified hierarchy, this type of memory needs to be included in the
tracking/accounting of a cgroup under active memory resource control.
Overhead is only incurred when a non-root control group is created AND
the memory controller is instructed to track and account the memory
footprint of that group. cgroup.memory=nosocket can be specified on
the boot commandline to override any runtime configuration and
forcibly exclude socket memory from active memory resource control.
Do you have any numbers about the overhead?
Hm? Performance numbers make sense when you have a specific scenario
and a theory on how to optimize the implementation for it.
The fact that there was a strong push to use static branches to put
the code out of line to reduce an overhead before the feature was
merged shows that people are sensitive to network performance and that
significant effort has been spent to eliminate it. My point was that you
are enabling the feature for all memcg users in unified hierarchy now
without having a performance impact overview which users can use
to judge whether to keep it enabled or disable before they start seeing
regressions or to make regression easier to track once it happens.
What load would you test and what would be the baseline to compare it
to?
It seems like netperf with a stream load running in a memcg with no
limits vs. in root memcg (and no other cgroups) should give at least a
hint about the runtime overhead, no?
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-18 18:28:09
On Wed, Nov 18, 2015 at 07:02:54PM +0300, Vladimir Davydov wrote:
On Tue, Nov 17, 2015 at 05:22:17PM -0500, Johannes Weiner wrote:
quoted
On Tue, Nov 17, 2015 at 11:18:50PM +0300, Vladimir Davydov wrote:
quoted
And with this patch it will work this way, but only if sum limits <
total ram, which is rather rare in practice. On tightly packed
systems it does nothing.
That's not true, it's still useful when things go south inside a
cgroup, even with overcommitted limits. See above.
I meant solely this patch here, not the rest of the patch set. In the
overcommitted case there is no difference if we have the last patch or
not AFAIU.
Even this patch, and even in the overcommitted case. When things go
bad inside a cgroup it can steal free memory (it's rare that machines
are at 100% utilization in practice) or memory from other groups until
it hits its own limit. I expect most users except, for some largescale
deployments, to frequently hit memory.high (or max) in practice.
Obviously the utopian case of full utilization will be even smoother
when we make vmpressure more finegrained, but why would that be an
argument *against* this patch here, which is useful everywhere else?
Why can't we apply all patches but the last one (they look OK at first
glance, but I need more time to review them carefully) and disable
socket accounting by default for now? Then you or someone else would
prepare a separate patch set introducing vmpressure propagation to
socket code, so that socket accounting could be enabled by default.
This is not going to happen, and we discussed this several times
before. I really wish Michal and you would put more thought into
interface implications. It's trivial to fix up implementation if
actual shortcomings are observed, but it's nigh impossible to fix
interfaces and user-visible behavior once published. It requires
enormous undertakings such as unified hierarchy to rectify things.
Please take your time to review this series, no problem.
But I'm no longer reacting to suggestions to make interface tradeoffs
because new code is not proven to work 99% of the time. That's simply
ridiculous. Any problems will have to be fixed either way, and we're
giving users the cmdline options to work around them in the meantime.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-18 21:48:37
On Wed, Nov 18, 2015 at 05:22:56PM +0100, Michal Hocko wrote:
On Mon 16-11-15 13:18:10, Johannes Weiner wrote:
quoted
What load would you test and what would be the baseline to compare it
to?
It seems like netperf with a stream load running in a memcg with no
limits vs. in root memcg (and no other cgroups) should give at least a
hint about the runtime overhead, no?
Comparing root vs. dedicated group generally doesn't make sense since
you either need containment or you don't. It makes more sense to test
both times inside a memory-controlled cgroup, one with a regular boot,
one with cgroup.memory=nosocket.
So I ran perf record -g -a netperf -t TCP_STREAM multiple times inside
a memory-controlled cgroup, but mostly mem_cgroup_charge_skmem() does
not show up in the profile at all. Once it was there with 0.00%.
I ran another test that downloads the latest kernel image from
kernel.org at 13MB/s (on my i5 laptop) and it looks like this:
0.02% 0.01% irq/44-iwlwifi [kernel.kallsyms] [k] mem_cgroup_charge_skmem
|
---mem_cgroup_charge_skmem
__sk_mem_schedule
tcp_try_rmem_schedule
tcp_data_queue
tcp_rcv_established
tcp_v4_do_rcv
tcp_v4_rcv
ip_local_deliver
ip_rcv
__netif_receive_skb_core
__netif_receive_skb
netif_receive_skb_internal
napi_gro_complete
The runs vary too much for this to be measurable in elapsed time.
From: Michal Hocko <mhocko@kernel.org> Date: 2015-11-19 13:50:29
On Wed 18-11-15 16:48:22, Johannes Weiner wrote:
[...]
So I ran perf record -g -a netperf -t TCP_STREAM multiple times inside
a memory-controlled cgroup, but mostly mem_cgroup_charge_skmem() does
not show up in the profile at all. Once it was there with 0.00%.
OK, this sounds very good! This means that most workloads which are not
focusing solely on the network traffic shouldn't even notice. I can
imagine that workloads with high throughput demands would notice but I
would also expect them to disable the feature.
Could you add this information to the changelog, please?
I ran another test that downloads the latest kernel image from
kernel.org at 13MB/s (on my i5 laptop) and it looks like this:
0.02% 0.01% irq/44-iwlwifi [kernel.kallsyms] [k] mem_cgroup_charge_skmem
|
---mem_cgroup_charge_skmem
__sk_mem_schedule
tcp_try_rmem_schedule
tcp_data_queue
tcp_rcv_established
tcp_v4_do_rcv
tcp_v4_rcv
ip_local_deliver
ip_rcv
__netif_receive_skb_core
__netif_receive_skb
netif_receive_skb_internal
napi_gro_complete
The runs vary too much for this to be measurable in elapsed time.
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-19 16:52:39
On Thu, Nov 19, 2015 at 02:50:24PM +0100, Michal Hocko wrote:
On Wed 18-11-15 16:48:22, Johannes Weiner wrote:
[...]
quoted
So I ran perf record -g -a netperf -t TCP_STREAM multiple times inside
a memory-controlled cgroup, but mostly mem_cgroup_charge_skmem() does
not show up in the profile at all. Once it was there with 0.00%.
OK, this sounds very good! This means that most workloads which are not
focusing solely on the network traffic shouldn't even notice. I can
imagine that workloads with high throughput demands would notice but I
would also expect them to disable the feature.
Even for high throughput, the cost of this is a function of number of
packets sent. E.g. the 13MB/s over wifi showed the socket charging at
0.02%. But I just did an http transfer over 1Gbit ethernet at around
110MB/s, ten times the bandwidth, and the charge function is at 0.00%.
Could you add this information to the changelog, please?
Sure, but which information exactly?
If we had found a realistic networking workload that is expected to be
containerized and had shown that load to be negatively affected by the
charging calls, that would have been worth bringing up in conjunction
with the boot-time flag. But what do we have to say here? People care
about cost. It seems unnecessary to point out the absence of it.
From: Vladimir Davydov <hidden> Date: 2015-11-20 09:08:00
On Thu, Nov 12, 2015 at 06:41:23PM -0500, Johannes Weiner wrote:
When a cgroup currently breaches its socket memory limit, it enters
memory pressure mode for itself and its *ancestors*. This throttles
transmission in unrelated sibling and cousin subtrees that have
nothing to do with the breached limit.
On the contrary, breaching a limit should make that group and its
*children* enter memory pressure mode. But this happens already,
albeit lazily: if an ancestor limit is breached, siblings will enter
memory pressure on their own once the next packet arrives for them.
Hmm, we still call sk_prot->enter_memory_pressure, which might hurt a
workload in the root cgroup AFAICS. Strange. You fix it in patch 8
though.
So no additional hierarchy code is needed. Remove the bogus stuff.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-20 09:48:41
On Thu, Nov 12, 2015 at 06:41:25PM -0500, Johannes Weiner wrote:
The number of allocated sockets is used for calculations in the soft
limit phase, where packets are accepted but the socket is under memory
pressure. Since there is no soft limit phase in tcp_memcontrol, and
memory pressure is only entered when packets are already dropped, this
is actually dead code. Remove it.
Actually, we can get into the soft limit phase due to the global limit
(tcp_memory_pressure is set), but then using per-memcg sockets_allocated
counter is just wrong.
As this is the last user of parent_cg_proto(), remove that too.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-20 09:52:18
On Thu, Nov 12, 2015 at 06:41:26PM -0500, Johannes Weiner wrote:
tcp_memcontrol replicates the global sysctl_mem limit array per
cgroup, but it only ever sets these entries to the value of the
memory_allocated page_counter limit. Use the latter directly.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
From: Vladimir Davydov <hidden> Date: 2015-11-20 10:59:19
On Thu, Nov 12, 2015 at 06:41:27PM -0500, Johannes Weiner wrote:
There won't be a tcp control soft limit, so integrating the memcg code
into the global skmem limiting scheme complicates things
unnecessarily. Replace this with simple and clear charge and uncharge
calls--hidden behind a jump label--to account skb memory.
Note that this is not purely aesthetic: as a result of shoehorning the
per-memcg code into the same memory accounting functions that handle
the global level, the old code would compare the per-memcg consumption
against the smaller of the per-memcg limit and the global limit. This
allowed the total consumption of multiple sockets to exceed the global
limit, as long as the individual sockets stayed within bounds. After
this change, the code will always compare the per-memcg consumption to
the per-memcg limit, and the global consumption to the global limit,
and thus close this loophole.
Without a soft limit, the per-memcg memory pressure state in sockets
is generally questionable. However, we did it until now, so we
continue to enter it when the hard limit is hit, and packets are
dropped, to let other sockets in the cgroup know that they shouldn't
grow their transmit windows, either. However, keep it simple in the
new callback model and leave memory pressure lazily when the next
packet is accepted (as opposed to doing it synchroneously when packets
are processed). When packets are dropped, network performance will
already be in the toilet, so that should be a reasonable trade-off.
As described above, consumption is now checked on the per-memcg level
and the global level separately. Likewise, memory pressure states are
maintained on both the per-memcg level and the global level, and a
socket is considered under pressure when either level asserts as much.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
It leaves the legacy functionality intact, while making the code look
much better.
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-20 12:42:34
On Thu, Nov 12, 2015 at 06:41:28PM -0500, Johannes Weiner wrote:
There won't be any separate counters for socket memory consumed by
protocols other than TCP in the future. Remove the indirection and
I really want to believe you're right. And with vmpressure propagation
implemented properly you are likely to be right.
However, we might still want to account other socket protos to
memcg->memory in the unified hierarchy, e.g. UDP, or SCTP, or whatever
else. Adding new consumers should be trivial, but it will break the
legacy usecase, where only TCP sockets are supposed to be accounted.
What about adding a check to sock_update_memcg() so that it would enable
accounting only for TCP sockets in case legacy hierarchy is used?
For the same reason, I think we'd better rename memcg->tcp_mem to
something like memcg->sk_mem or we can even drop the cg_proto struct
altogether embedding its fields directly to mem_cgroup struct.
Also, I don't see any reason to have tcp_memcontrol.c file. It's tiny
and with this patch it does not depend on tcp code any more. Let's move
it to memcontrol.c?
Other than that this patch looks OK to me.
Thanks,
Vladimir
link sockets directly to their owning memory cgroup.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-20 12:45:05
On Thu, Nov 12, 2015 at 06:41:31PM -0500, Johannes Weiner wrote:
The unified hierarchy memory controller will account socket
memory. Move the infrastructure functions accordingly.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Vladimir Davydov <redacted>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-20 13:10:57
On Thu, Nov 12, 2015 at 06:41:32PM -0500, Johannes Weiner wrote:
...
quoted hunk
@@ -5514,16 +5550,43 @@ void sock_release_memcg(struct sock *sk) */ bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages) {+ unsigned int batch = max(CHARGE_BATCH, nr_pages); struct page_counter *counter;+ bool force = false;- if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,- nr_pages, &counter)) {- memcg->tcp_mem.memory_pressure = 0;+#ifdef CONFIG_MEMCG_KMEM+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {+ if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,+ nr_pages, &counter)) {+ memcg->tcp_mem.memory_pressure = 0;+ return true;+ }+ page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);+ memcg->tcp_mem.memory_pressure = 1;+ return false;+ }+#endif+ if (consume_stock(memcg, nr_pages)) return true;+retry:+ if (page_counter_try_charge(&memcg->memory, batch, &counter))+ goto done;++ if (batch > nr_pages) {+ batch = nr_pages;+ goto retry; }- page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);- memcg->tcp_mem.memory_pressure = 1;- return false;++ page_counter_charge(&memcg->memory, batch);+ force = true;+done:
+ css_get_many(&memcg->css, batch);
Is there any point to get css reference per each charged page? For kmem
it is absolutely necessary, because dangling slabs must block
destruction of memcg's kmem caches, which are destroyed on css_free. But
for sockets there's no such problem: memcg will be destroyed only after
all sockets are destroyed and therefore uncharged (since
sock_update_memcg pins css).
I think it's suboptimal to schedule the work even if we are below the
high threshold.
BTW why do we need this work at all? Why is reclaim_high called from
task_work not enough?
Thanks,
Vladimir
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-20 18:43:10
On Fri, Nov 20, 2015 at 01:58:57PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:27PM -0500, Johannes Weiner wrote:
quoted
There won't be a tcp control soft limit, so integrating the memcg code
into the global skmem limiting scheme complicates things
unnecessarily. Replace this with simple and clear charge and uncharge
calls--hidden behind a jump label--to account skb memory.
Note that this is not purely aesthetic: as a result of shoehorning the
per-memcg code into the same memory accounting functions that handle
the global level, the old code would compare the per-memcg consumption
against the smaller of the per-memcg limit and the global limit. This
allowed the total consumption of multiple sockets to exceed the global
limit, as long as the individual sockets stayed within bounds. After
this change, the code will always compare the per-memcg consumption to
the per-memcg limit, and the global consumption to the global limit,
and thus close this loophole.
Without a soft limit, the per-memcg memory pressure state in sockets
is generally questionable. However, we did it until now, so we
continue to enter it when the hard limit is hit, and packets are
dropped, to let other sockets in the cgroup know that they shouldn't
grow their transmit windows, either. However, keep it simple in the
new callback model and leave memory pressure lazily when the next
packet is accepted (as opposed to doing it synchroneously when packets
are processed). When packets are dropped, network performance will
already be in the toilet, so that should be a reasonable trade-off.
As described above, consumption is now checked on the per-memcg level
and the global level separately. Likewise, memory pressure states are
maintained on both the per-memcg level and the global level, and a
socket is considered under pressure when either level asserts as much.
Signed-off-by: Johannes Weiner <redacted>
It leaves the legacy functionality intact, while making the code look
much better.
Reviewed-by: Vladimir Davydov <redacted>
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-20 18:57:02
On Fri, Nov 20, 2015 at 03:42:16PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:28PM -0500, Johannes Weiner wrote:
quoted
There won't be any separate counters for socket memory consumed by
protocols other than TCP in the future. Remove the indirection and
I really want to believe you're right. And with vmpressure propagation
implemented properly you are likely to be right.
However, we might still want to account other socket protos to
memcg->memory in the unified hierarchy, e.g. UDP, or SCTP, or whatever
else. Adding new consumers should be trivial, but it will break the
legacy usecase, where only TCP sockets are supposed to be accounted.
What about adding a check to sock_update_memcg() so that it would enable
accounting only for TCP sockets in case legacy hierarchy is used?
Yup, I was thinking the same thing. But we can cross that bridge when
we come to it and are actually adding further packet types.
For the same reason, I think we'd better rename memcg->tcp_mem to
something like memcg->sk_mem or we can even drop the cg_proto struct
altogether embedding its fields directly to mem_cgroup struct.
Also, I don't see any reason to have tcp_memcontrol.c file. It's tiny
and with this patch it does not depend on tcp code any more. Let's move
it to memcontrol.c?
I actually had all this at first, but then wondered if it makes more
sense to keep the legacy code in isolation. Don't you think it would
be easier to keep track of what's v1 and what's v2 if we keep the
legacy stuff physically separate as much as possible? In particular I
found that 'tcp_mem.' marker really useful while working on the code.
In the same vein, tcp_memcontrol.c doesn't really hurt anybody and I'd
expect it to remain mostly unopened and unchanged in the future. But
if we merge it into memcontrol.c, that code will likely be in the way
and we'd have to make it explicit somehow that this is not actually
part of the new memory controller anymore.
What do you think?
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-20 19:25:22
On Fri, Nov 20, 2015 at 04:10:33PM +0300, Vladimir Davydov wrote:
On Thu, Nov 12, 2015 at 06:41:32PM -0500, Johannes Weiner wrote:
...
quoted
@@ -5514,16 +5550,43 @@ void sock_release_memcg(struct sock *sk) */ bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages) {+ unsigned int batch = max(CHARGE_BATCH, nr_pages); struct page_counter *counter;+ bool force = false;- if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,- nr_pages, &counter)) {- memcg->tcp_mem.memory_pressure = 0;+#ifdef CONFIG_MEMCG_KMEM+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {+ if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,+ nr_pages, &counter)) {+ memcg->tcp_mem.memory_pressure = 0;+ return true;+ }+ page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);+ memcg->tcp_mem.memory_pressure = 1;+ return false;+ }+#endif+ if (consume_stock(memcg, nr_pages)) return true;+retry:+ if (page_counter_try_charge(&memcg->memory, batch, &counter))+ goto done;++ if (batch > nr_pages) {+ batch = nr_pages;+ goto retry; }- page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);- memcg->tcp_mem.memory_pressure = 1;- return false;++ page_counter_charge(&memcg->memory, batch);+ force = true;+done:
quoted
+ css_get_many(&memcg->css, batch);
Is there any point to get css reference per each charged page? For kmem
it is absolutely necessary, because dangling slabs must block
destruction of memcg's kmem caches, which are destroyed on css_free. But
for sockets there's no such problem: memcg will be destroyed only after
all sockets are destroyed and therefore uncharged (since
sock_update_memcg pins css).
I'm afraid we have to when we want to share 'stock' with cache and
anon pages, which hold individual references. drain_stock() always
assumes one reference per cached page.
I think it's suboptimal to schedule the work even if we are below the
high threshold.
Hm, it seemed unnecessary to duplicate the hierarchy check since this
is in the batch-exhausted slowpath anyway.
BTW why do we need this work at all? Why is reclaim_high called from
task_work not enough?
The problem lies in the memcg association: the random task that gets
interrupted by an arriving packet might not be in the same memcg as
the one owning receiving socket. And multiple interrupts could happen
while we're in the kernel already charging pages. We'd basically have
to maintain a list of memcgs that need to run reclaim_high associated
with current.
From: Vladimir Davydov <hidden> Date: 2015-11-23 09:37:11
On Fri, Nov 20, 2015 at 01:56:48PM -0500, Johannes Weiner wrote:
On Fri, Nov 20, 2015 at 03:42:16PM +0300, Vladimir Davydov wrote:
quoted
On Thu, Nov 12, 2015 at 06:41:28PM -0500, Johannes Weiner wrote:
quoted
There won't be any separate counters for socket memory consumed by
protocols other than TCP in the future. Remove the indirection and
I really want to believe you're right. And with vmpressure propagation
implemented properly you are likely to be right.
However, we might still want to account other socket protos to
memcg->memory in the unified hierarchy, e.g. UDP, or SCTP, or whatever
else. Adding new consumers should be trivial, but it will break the
legacy usecase, where only TCP sockets are supposed to be accounted.
What about adding a check to sock_update_memcg() so that it would enable
accounting only for TCP sockets in case legacy hierarchy is used?
Yup, I was thinking the same thing. But we can cross that bridge when
we come to it and are actually adding further packet types.
Fair enough.
quoted
For the same reason, I think we'd better rename memcg->tcp_mem to
something like memcg->sk_mem or we can even drop the cg_proto struct
altogether embedding its fields directly to mem_cgroup struct.
Also, I don't see any reason to have tcp_memcontrol.c file. It's tiny
and with this patch it does not depend on tcp code any more. Let's move
it to memcontrol.c?
I actually had all this at first, but then wondered if it makes more
sense to keep the legacy code in isolation. Don't you think it would
be easier to keep track of what's v1 and what's v2 if we keep the
legacy stuff physically separate as much as possible? In particular I
found that 'tcp_mem.' marker really useful while working on the code.
In the same vein, tcp_memcontrol.c doesn't really hurt anybody and I'd
expect it to remain mostly unopened and unchanged in the future. But
if we merge it into memcontrol.c, that code will likely be in the way
and we'd have to make it explicit somehow that this is not actually
part of the new memory controller anymore.
What do you think?
There isn't much code left in tcp_memcontrol.c, and not all of it is
legacy. We still want to call tcp_init_cgroup and tcp_destroy_cgroup
from memcontrol.c - in fact, it's the only call site, so I think we'd
better keep these functions there. Apart from init/destroy, there is
only stuff for handling legacy files, which is relatively small and
isolated. We can just put it along with memsw and kmem legacy files in
the end of memcontrol.c adding a comment that it's legacy. Personally,
I'd find the code easier to follow then, because currently the logic
behind the ACTIVE flag as well as memcg->tcp_mem init/use/destroy turns
out to be scattered between two files in different subsystems for no
apparent reason now, as it does not need tcp_prot any more. Besides,
this would allow us to accurately reuse the ACTIVE flag in init/destroy
for inc/dec static branch and probably in sock_update_memcg instead of
sprinkling cgroup_subsys_on_dfl all over the place, which would make the
code a bit cleaner IMO (in fact, that's why I proposed to drop ACTIVATED
bit and replace cg_proto->flags with ->active bool).
Regarding, tcp_mem marker, well, currently it's OK, because we don't
account anything but TCP sockets, but when it changes (and I'm pretty
sure it will), we'll have to rename it anyway. For now, I'm OK with
leaving it as is though.
Thanks,
Vladimir
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-23 10:01:21
On Fri, Nov 20, 2015 at 02:25:06PM -0500, Johannes Weiner wrote:
On Fri, Nov 20, 2015 at 04:10:33PM +0300, Vladimir Davydov wrote:
quoted
On Thu, Nov 12, 2015 at 06:41:32PM -0500, Johannes Weiner wrote:
...
quoted
@@ -5514,16 +5550,43 @@ void sock_release_memcg(struct sock *sk) */ bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages) {+ unsigned int batch = max(CHARGE_BATCH, nr_pages); struct page_counter *counter;+ bool force = false;- if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,- nr_pages, &counter)) {- memcg->tcp_mem.memory_pressure = 0;+#ifdef CONFIG_MEMCG_KMEM+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) {+ if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,+ nr_pages, &counter)) {+ memcg->tcp_mem.memory_pressure = 0;+ return true;+ }+ page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);+ memcg->tcp_mem.memory_pressure = 1;+ return false;+ }+#endif+ if (consume_stock(memcg, nr_pages)) return true;+retry:+ if (page_counter_try_charge(&memcg->memory, batch, &counter))+ goto done;++ if (batch > nr_pages) {+ batch = nr_pages;+ goto retry; }- page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);- memcg->tcp_mem.memory_pressure = 1;- return false;++ page_counter_charge(&memcg->memory, batch);+ force = true;+done:
quoted
+ css_get_many(&memcg->css, batch);
Is there any point to get css reference per each charged page? For kmem
it is absolutely necessary, because dangling slabs must block
destruction of memcg's kmem caches, which are destroyed on css_free. But
for sockets there's no such problem: memcg will be destroyed only after
all sockets are destroyed and therefore uncharged (since
sock_update_memcg pins css).
I'm afraid we have to when we want to share 'stock' with cache and
anon pages, which hold individual references. drain_stock() always
assumes one reference per cached page.
I think it's suboptimal to schedule the work even if we are below the
high threshold.
Hm, it seemed unnecessary to duplicate the hierarchy check since this
is in the batch-exhausted slowpath anyway.
Dunno, may be you're right.
I've another question regarding this socket_work: its reclaim target
always equals CHARGE_BATCH. Can't it result in a workload exceeding
memory.high in case there are a lot of allocations coming from different
cpus? In this case the work might not manage to complete before another
allocation happens. May be, we should accumulate the number of pages to
be reclaimed by the work, as we do in try_charge?
quoted
BTW why do we need this work at all? Why is reclaim_high called from
task_work not enough?
The problem lies in the memcg association: the random task that gets
interrupted by an arriving packet might not be in the same memcg as
the one owning receiving socket. And multiple interrupts could happen
while we're in the kernel already charging pages. We'd basically have
to maintain a list of memcgs that need to run reclaim_high associated
with current.
Right, I think this is worth placing in a comment to memcg->socket_work.
I wonder if we could use it *instead* of task_work for handling every
allocation, not only socket-related. Would it make any sense? May be, it
could reduce the latency experienced by tasks in memory cgroups.
Thanks,
Vladimir
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-23 18:20:55
On Mon, Nov 23, 2015 at 12:36:46PM +0300, Vladimir Davydov wrote:
On Fri, Nov 20, 2015 at 01:56:48PM -0500, Johannes Weiner wrote:
quoted
I actually had all this at first, but then wondered if it makes more
sense to keep the legacy code in isolation. Don't you think it would
be easier to keep track of what's v1 and what's v2 if we keep the
legacy stuff physically separate as much as possible? In particular I
found that 'tcp_mem.' marker really useful while working on the code.
In the same vein, tcp_memcontrol.c doesn't really hurt anybody and I'd
expect it to remain mostly unopened and unchanged in the future. But
if we merge it into memcontrol.c, that code will likely be in the way
and we'd have to make it explicit somehow that this is not actually
part of the new memory controller anymore.
What do you think?
There isn't much code left in tcp_memcontrol.c, and not all of it is
legacy. We still want to call tcp_init_cgroup and tcp_destroy_cgroup
from memcontrol.c - in fact, it's the only call site, so I think we'd
better keep these functions there. Apart from init/destroy, there is
only stuff for handling legacy files, which is relatively small and
isolated. We can just put it along with memsw and kmem legacy files in
the end of memcontrol.c adding a comment that it's legacy. Personally,
I'd find the code easier to follow then, because currently the logic
behind the ACTIVE flag as well as memcg->tcp_mem init/use/destroy turns
out to be scattered between two files in different subsystems for no
apparent reason now, as it does not need tcp_prot any more. Besides,
this would allow us to accurately reuse the ACTIVE flag in init/destroy
for inc/dec static branch and probably in sock_update_memcg instead of
sprinkling cgroup_subsys_on_dfl all over the place, which would make the
code a bit cleaner IMO (in fact, that's why I proposed to drop ACTIVATED
bit and replace cg_proto->flags with ->active bool).
As far as I can see, all of tcp_memcontrol.c is legacy, including the
init and destroy functions. We only call them to set up the legacy
tcp_mem state and do legacy jump-label maintenance. Delete it all and
the unified hierarchy controller would still work. So I don't really
see the benefits of consolidating it, and more risk of convoluting.
That being said, if you care strongly about it and see opportunities
to cut down code and make things more readable, please feel free to
turn the flags -> bool patch into a followup series and I'll be happy
to review it.
Thanks!
From: Johannes Weiner <hannes@cmpxchg.org> Date: 2015-11-23 19:31:40
On Mon, Nov 23, 2015 at 01:00:59PM +0300, Vladimir Davydov wrote:
I've another question regarding this socket_work: its reclaim target
always equals CHARGE_BATCH. Can't it result in a workload exceeding
memory.high in case there are a lot of allocations coming from different
cpus? In this case the work might not manage to complete before another
allocation happens. May be, we should accumulate the number of pages to
be reclaimed by the work, as we do in try_charge?
Actually, try_to_free_mem_cgroup_pages() rounds it up to 2MB anyway. I
would hate to add locking or more atomics to accumulate a reclaim goal
for the worker on spec, so let's wait to see if this is a real issue.
quoted
quoted
BTW why do we need this work at all? Why is reclaim_high called from
task_work not enough?
The problem lies in the memcg association: the random task that gets
interrupted by an arriving packet might not be in the same memcg as
the one owning receiving socket. And multiple interrupts could happen
while we're in the kernel already charging pages. We'd basically have
to maintain a list of memcgs that need to run reclaim_high associated
with current.
Right, I think this is worth placing in a comment to memcg->socket_work.
Okay, will do.
I wonder if we could use it *instead* of task_work for handling every
allocation, not only socket-related. Would it make any sense? May be, it
could reduce the latency experienced by tasks in memory cgroups.
No, we *want* charging tasks to do reclaim work once memory.high is
breached, in order to match their speed to memory availability. That
needs to remain synchroneous.
What we could try is make memcg->socket_work purely about the receive
side when we're inside the softirq, and arm the per-task work when in
process context on the sending side. I'll look into that.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Vladimir Davydov <hidden> Date: 2015-11-24 13:43:49
On Mon, Nov 23, 2015 at 01:20:37PM -0500, Johannes Weiner wrote:
On Mon, Nov 23, 2015 at 12:36:46PM +0300, Vladimir Davydov wrote:
quoted
On Fri, Nov 20, 2015 at 01:56:48PM -0500, Johannes Weiner wrote:
quoted
I actually had all this at first, but then wondered if it makes more
sense to keep the legacy code in isolation. Don't you think it would
be easier to keep track of what's v1 and what's v2 if we keep the
legacy stuff physically separate as much as possible? In particular I
found that 'tcp_mem.' marker really useful while working on the code.
In the same vein, tcp_memcontrol.c doesn't really hurt anybody and I'd
expect it to remain mostly unopened and unchanged in the future. But
if we merge it into memcontrol.c, that code will likely be in the way
and we'd have to make it explicit somehow that this is not actually
part of the new memory controller anymore.
What do you think?
There isn't much code left in tcp_memcontrol.c, and not all of it is
legacy. We still want to call tcp_init_cgroup and tcp_destroy_cgroup
from memcontrol.c - in fact, it's the only call site, so I think we'd
better keep these functions there. Apart from init/destroy, there is
only stuff for handling legacy files, which is relatively small and
isolated. We can just put it along with memsw and kmem legacy files in
the end of memcontrol.c adding a comment that it's legacy. Personally,
I'd find the code easier to follow then, because currently the logic
behind the ACTIVE flag as well as memcg->tcp_mem init/use/destroy turns
out to be scattered between two files in different subsystems for no
apparent reason now, as it does not need tcp_prot any more. Besides,
this would allow us to accurately reuse the ACTIVE flag in init/destroy
for inc/dec static branch and probably in sock_update_memcg instead of
sprinkling cgroup_subsys_on_dfl all over the place, which would make the
code a bit cleaner IMO (in fact, that's why I proposed to drop ACTIVATED
bit and replace cg_proto->flags with ->active bool).
As far as I can see, all of tcp_memcontrol.c is legacy, including the
init and destroy functions. We only call them to set up the legacy
tcp_mem state and do legacy jump-label maintenance. Delete it all and
the unified hierarchy controller would still work. So I don't really
see the benefits of consolidating it, and more risk of convoluting.
That being said, if you care strongly about it and see opportunities
to cut down code and make things more readable, please feel free to
turn the flags -> bool patch into a followup series and I'll be happy
to review it.
OK, I'll look into that.
Regarding this patch, I don't have any questions left,
Reviewed-by: Vladimir Davydov <redacted>
Thanks,
Vladimir