From: Shakeel Butt <shakeelb@xxxxxxxxxx> commit d4a5b369ad6d8aae552752ff438dddde653a72ec upstream. One of our workloads (Postgres 14 + sysbench OLTP) regressed on newer upstream kernel and on further investigation, it seems like the cause is the always synchronous rstat flush in the count_shadow_nodes() added by the commit f82e6bf9bb9b ("mm: memcg: use rstat for non-hierarchical stats"). On further inspection it seems like we don't really need accurate stats in this function as it was already approximating the amount of appropriate shadow entries to keep for maintaining the refault information. Since there is already 2 sec periodic rstat flush, we don't need exact stats here. Let's ratelimit the rstat flush in this code path. Link: https://lkml.kernel.org/r/20231228073055.4046430-1-shakeelb@xxxxxxxxxx Fixes: f82e6bf9bb9b ("mm: memcg: use rstat for non-hierarchical stats") Signed-off-by: Shakeel Butt <shakeelb@xxxxxxxxxx> Cc: Johannes Weiner <hannes@xxxxxxxxxxx> Cc: Yosry Ahmed <yosryahmed@xxxxxxxxxx> Cc: Yu Zhao <yuzhao@xxxxxxxxxx> Cc: Michal Hocko <mhocko@xxxxxxxx> Cc: Roman Gushchin <roman.gushchin@xxxxxxxxx> Cc: Muchun Song <songmuchun@xxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Jesper Dangaard Brouer <hawk@xxxxxxxxxx> --- On production with kernel v6.6 we are observing issues with excessive cgroup rstat flushing due to the extra call to mem_cgroup_flush_stats() in count_shadow_nodes() introduced in commit f82e6bf9bb9b ("mm: memcg: use rstat for non-hierarchical stats") that commit is part of v6.6. We request backport of commit d4a5b369ad6d ("mm: ratelimit stat flush from workingset shrinker") as it have a fixes tag for this commit. IMHO it is worth explaining call path that makes count_shadow_nodes() cause excessive cgroup rstat flushing calls. Function shrink_node() calls mem_cgroup_flush_stats() on its own first, and then invokes shrink_node_memcgs(). Function shrink_node_memcgs() iterates over cgroups via mem_cgroup_iter() for each calling shrink_slab(). The shrink_slab() calls do_shrink_slab() that via shrinker->count_objects() invoke count_shadow_nodes(), and count_shadow_nodes() does a mem_cgroup_flush_stats() call, that seems unnecessary. Backport differs slightly due to v6.6.32 doesn't contain commit 7d7ef0a4686a ("mm: memcg: restore subtree stats flushing") from v6.8. --- mm/workingset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/workingset.c b/mm/workingset.c index 2559a1f2fc1c..9110957bec5b 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -664,7 +664,7 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker, struct lruvec *lruvec; int i; - mem_cgroup_flush_stats(); + mem_cgroup_flush_stats_ratelimited(); lruvec = mem_cgroup_lruvec(sc->memcg, NODE_DATA(sc->nid)); for (pages = 0, i = 0; i < NR_LRU_LISTS; i++) pages += lruvec_page_state_local(lruvec,