Skip to content

Commit 2fba596

Browse files
shakeelbakpm00
authored andcommitted
memcg: simplify consume_stock
Patch series "memcg: decouple memcg and objcg stocks", v3. The per-cpu memcg charge cache and objcg charge cache are coupled in a single struct memcg_stock_pcp and a single local lock is used to protect both of the caches. This makes memcg charging and objcg charging nmi safe challenging. Decoupling memcg and objcg stocks would allow us to make them nmi safe and even work without disabling irqs independently. This series completely decouples memcg and objcg stocks. To evaluate the impact of this series with and without PREEMPT_RT config, we ran varying number of netperf clients in different cgroups on a 72 CPU machine. $ netserver -6 $ netperf -6 -H ::1 -l 60 -t TCP_SENDFILE -- -m 10K PREEMPT_RT config: ------------------ number of clients | Without series | With series 6 | 38559.1 Mbps | 38652.6 Mbps 12 | 37388.8 Mbps | 37560.1 Mbps 18 | 30707.5 Mbps | 31378.3 Mbps 24 | 25908.4 Mbps | 26423.9 Mbps 30 | 22347.7 Mbps | 22326.5 Mbps 36 | 20235.1 Mbps | 20165.0 Mbps !PREEMPT_RT config: ------------------- number of clients | Without series | With series 6 | 50235.7 Mbps | 51415.4 Mbps 12 | 49336.5 Mbps | 49901.4 Mbps 18 | 46306.8 Mbps | 46482.7 Mbps 24 | 38145.7 Mbps | 38729.4 Mbps 30 | 30347.6 Mbps | 31698.2 Mbps 36 | 26976.6 Mbps | 27364.4 Mbps No performance regression was observed. This patch (of 4): consume_stock() does not need to check gfp_mask for spinning and can simply trylock the local lock to decide to proceed or fail. No need to spin at all for local lock. One of the concern raised was that on PREEMPT_RT kernels, this trylock can fail more often due to tasks having lock_lock can be preempted. This can potentially cause the task which have preempted the task having the local_lock to take the slow path of memcg charging. However this behavior will only impact the performance if memcg charging slowpath is worse than two context switches and possibly scheduling delay behavior of current code. From the network intensive workload experiment it does not seem like the case. We ran varying number of netperf clients in different cgroups on a 72 CPU machine for PREEMPT_RT config. $ netserver -6 $ netperf -6 -H ::1 -l 60 -t TCP_SENDFILE -- -m 10K number of clients | Without series | With series 6 | 38559.1 Mbps | 38652.6 Mbps 12 | 37388.8 Mbps | 37560.1 Mbps 18 | 30707.5 Mbps | 31378.3 Mbps 24 | 25908.4 Mbps | 26423.9 Mbps 30 | 22347.7 Mbps | 22326.5 Mbps 36 | 20235.1 Mbps | 20165.0 Mbps We don't see any significant performance difference for the network intensive workload with this series. Link: https://lkml.kernel.org/r/20250506225533.2580386-1-shakeel.butt@linux.dev Link: https://lkml.kernel.org/r/20250506225533.2580386-2-shakeel.butt@linux.dev Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Eric Dumaze <edumazet@google.com> Cc: Jakub Kacinski <kuba@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: Muchun Song <muchun.song@linux.dev> Cc: Roman Gushchin <roman.gushchin@linux.dev> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 0cad673 commit 2fba596

File tree

1 file changed

+7
-13
lines changed

1 file changed

+7
-13
lines changed

mm/memcontrol.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,29 +1806,23 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
18061806
* consume_stock: Try to consume stocked charge on this cpu.
18071807
* @memcg: memcg to consume from.
18081808
* @nr_pages: how many pages to charge.
1809-
* @gfp_mask: allocation mask.
18101809
*
1811-
* The charges will only happen if @memcg matches the current cpu's memcg
1812-
* stock, and at least @nr_pages are available in that stock. Failure to
1813-
* service an allocation will refill the stock.
1810+
* Consume the cached charge if enough nr_pages are present otherwise return
1811+
* failure. Also return failure for charge request larger than
1812+
* MEMCG_CHARGE_BATCH or if the local lock is already taken.
18141813
*
18151814
* returns true if successful, false otherwise.
18161815
*/
1817-
static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages,
1818-
gfp_t gfp_mask)
1816+
static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
18191817
{
18201818
struct memcg_stock_pcp *stock;
18211819
uint8_t stock_pages;
18221820
unsigned long flags;
18231821
bool ret = false;
18241822
int i;
18251823

1826-
if (nr_pages > MEMCG_CHARGE_BATCH)
1827-
return ret;
1828-
1829-
if (gfpflags_allow_spinning(gfp_mask))
1830-
local_lock_irqsave(&memcg_stock.stock_lock, flags);
1831-
else if (!local_trylock_irqsave(&memcg_stock.stock_lock, flags))
1824+
if (nr_pages > MEMCG_CHARGE_BATCH ||
1825+
!local_trylock_irqsave(&memcg_stock.stock_lock, flags))
18321826
return ret;
18331827

18341828
stock = this_cpu_ptr(&memcg_stock);
@@ -2331,7 +2325,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
23312325
unsigned long pflags;
23322326

23332327
retry:
2334-
if (consume_stock(memcg, nr_pages, gfp_mask))
2328+
if (consume_stock(memcg, nr_pages))
23352329
return 0;
23362330

23372331
if (!gfpflags_allow_spinning(gfp_mask))

0 commit comments

Comments
 (0)