* [PATCH v2 0/4] memcg: non-unified flushing for userspace stats
@ 2023-08-28 23:33 Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 1/4] mm: memcg: properly name and document unified stats flushing Yosry Ahmed
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Yosry Ahmed @ 2023-08-28 23:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Ivan Babrou, Tejun Heo, Michal Koutný,
Waiman Long, linux-mm, cgroups, linux-kernel, Yosry Ahmed
Most memcg flushing contexts using "unified" flushing, where only one
flusher is allowed at a time (others skip), and all flushers need to
flush the entire tree. This works well with high concurrency, which
mostly comes from in-kernel flushers (e.g. reclaim, refault, ..).
For userspace reads, unified flushing leads to non-deterministic stats
staleness and reading cost. This series clarifies and documents the
differences between unified and non-unified flushing (patches 1 & 2),
then opts userspace reads out of unified flushing (patch 3).
This patch series is a follow up on the discussion in [1]. That was a
patch that proposed that userspace reads wait for ongoing unified
flushers to complete before returning. There were concerns about the
latency that this introduces to userspace reads, especially with ongoing
reports of expensive stat reads even with unified flushing. Hence, this
series follows a different approach, by opting userspace reads out of
unified flushing completely. The cost of userspace reads are now
determinstic, and depend on the size of the subtree being read. This
should fix both the *sometimes* expensive reads (due to flushing the
entire tree) and occasional staless (due to skipping flushing).
I attempted to remove unified flushing completely, but noticed that
in-kernel flushers with high concurrency (e.g. hundreds of concurrent
reclaimers). This sort of concurrency is not expected from userspace
reads. More details about testing and some numbers in the last patch's
changelog.
v1 -> v2:
- Added patch 3 to help unified stats with non-unified root flushes
as suggested by Michal Koutný.
- Updated the last patch changelog after discussions with Michal Hocko,
Shakeel Butt, and Waiman Long.
Yosry Ahmed (4):
mm: memcg: properly name and document unified stats flushing
mm: memcg: add a helper for non-unified stats flushing
mm: memcg: let non-unified root stats flushes help unified flushes
mm: memcg: use non-unified stats flushing for userspace reads
include/linux/memcontrol.h | 8 ++--
mm/memcontrol.c | 83 ++++++++++++++++++++++++++------------
mm/vmscan.c | 2 +-
mm/workingset.c | 4 +-
4 files changed, 65 insertions(+), 32 deletions(-)
--
2.42.0.rc2.253.gd59a3bf2b4-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/4] mm: memcg: properly name and document unified stats flushing
2023-08-28 23:33 [PATCH v2 0/4] memcg: non-unified flushing for userspace stats Yosry Ahmed
@ 2023-08-28 23:33 ` Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 2/4] mm: memcg: add a helper for non-unified " Yosry Ahmed
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Yosry Ahmed @ 2023-08-28 23:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Ivan Babrou, Tejun Heo, Michal Koutný,
Waiman Long, linux-mm, cgroups, linux-kernel, Yosry Ahmed
Most contexts that flush memcg stats use "unified" flushing, where
basically all flushers attempt to flush the entire hierarchy, but only
one flusher is allowed at a time, others skip flushing.
This is needed because we need to flush the stats from paths such as
reclaim or refaults, which may have high concurrency, especially on
large systems. Serializing such performance-sensitive paths can
introduce regressions, hence, unified flushing offers a tradeoff between
stats staleness and the performance impact of flushing stats.
Document this properly and explicitly by renaming the common flushing
helper from do_flush_stats() to do_unified_stats_flush(), and adding
documentation to describe unified flushing. Additionally, rename
flushing APIs to add "try" in the name, which implies that flushing will
not always happen. Also add proper documentation.
No functional change intended.
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
include/linux/memcontrol.h | 8 +++---
mm/memcontrol.c | 53 ++++++++++++++++++++++++++------------
mm/vmscan.c | 2 +-
mm/workingset.c | 4 +--
4 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 11810a2cfd2d..d517b0cc5221 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -1034,8 +1034,8 @@ static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
return x;
}
-void mem_cgroup_flush_stats(void);
-void mem_cgroup_flush_stats_ratelimited(void);
+void mem_cgroup_try_flush_stats(void);
+void mem_cgroup_try_flush_stats_ratelimited(void);
void __mod_memcg_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
int val);
@@ -1519,11 +1519,11 @@ static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
return node_page_state(lruvec_pgdat(lruvec), idx);
}
-static inline void mem_cgroup_flush_stats(void)
+static inline void mem_cgroup_try_flush_stats(void)
{
}
-static inline void mem_cgroup_flush_stats_ratelimited(void)
+static inline void mem_cgroup_try_flush_stats_ratelimited(void)
{
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index cf57fe9318d5..c6150ea54d48 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -630,7 +630,7 @@ static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
/*
* If stats_flush_threshold exceeds the threshold
* (>num_online_cpus()), cgroup stats update will be triggered
- * in __mem_cgroup_flush_stats(). Increasing this var further
+ * in mem_cgroup_try_flush_stats(). Increasing this var further
* is redundant and simply adds overhead in atomic update.
*/
if (atomic_read(&stats_flush_threshold) <= num_online_cpus())
@@ -639,13 +639,17 @@ static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
}
}
-static void do_flush_stats(void)
+/*
+ * do_unified_stats_flush - do a unified flush of memory cgroup statistics
+ *
+ * A unified flush tries to flush the entire hierarchy, but skips if there is
+ * another ongoing flush. This is meant for flushers that may have a lot of
+ * concurrency (e.g. reclaim, refault, etc), and should not be serialized to
+ * avoid slowing down performance-sensitive paths. A unified flush may skip, and
+ * hence may yield stale stats.
+ */
+static void do_unified_stats_flush(void)
{
- /*
- * We always flush the entire tree, so concurrent flushers can just
- * skip. This avoids a thundering herd problem on the rstat global lock
- * from memcg flushers (e.g. reclaim, refault, etc).
- */
if (atomic_read(&stats_flush_ongoing) ||
atomic_xchg(&stats_flush_ongoing, 1))
return;
@@ -658,16 +662,31 @@ static void do_flush_stats(void)
atomic_set(&stats_flush_ongoing, 0);
}
-void mem_cgroup_flush_stats(void)
+/*
+ * mem_cgroup_try_flush_stats - try to flush memory cgroup statistics
+ *
+ * Try to flush the stats of all memcgs that have stat updates since the last
+ * flush. We do not flush the stats if:
+ * - The magnitude of the pending updates is below a certain threshold.
+ * - There is another ongoing unified flush (see do_unified_stats_flush()).
+ *
+ * Hence, the stats may be stale, but ideally by less than FLUSH_TIME due to
+ * periodic flushing.
+ */
+void mem_cgroup_try_flush_stats(void)
{
if (atomic_read(&stats_flush_threshold) > num_online_cpus())
- do_flush_stats();
+ do_unified_stats_flush();
}
-void mem_cgroup_flush_stats_ratelimited(void)
+/*
+ * Like mem_cgroup_try_flush_stats(), but only flushes if the periodic flusher
+ * is late.
+ */
+void mem_cgroup_try_flush_stats_ratelimited(void)
{
if (time_after64(jiffies_64, READ_ONCE(flush_next_time)))
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
}
static void flush_memcg_stats_dwork(struct work_struct *w)
@@ -676,7 +695,7 @@ static void flush_memcg_stats_dwork(struct work_struct *w)
* Always flush here so that flushing in latency-sensitive paths is
* as cheap as possible.
*/
- do_flush_stats();
+ do_unified_stats_flush();
queue_delayed_work(system_unbound_wq, &stats_flush_dwork, FLUSH_TIME);
}
@@ -1576,7 +1595,7 @@ static void memcg_stat_format(struct mem_cgroup *memcg, struct seq_buf *s)
*
* Current memory state:
*/
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
for (i = 0; i < ARRAY_SIZE(memory_stats); i++) {
u64 size;
@@ -4018,7 +4037,7 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v)
int nid;
struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
for (stat = stats; stat < stats + ARRAY_SIZE(stats); stat++) {
seq_printf(m, "%s=%lu", stat->name,
@@ -4093,7 +4112,7 @@ static void memcg1_stat_format(struct mem_cgroup *memcg, struct seq_buf *s)
BUILD_BUG_ON(ARRAY_SIZE(memcg1_stat_names) != ARRAY_SIZE(memcg1_stats));
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
unsigned long nr;
@@ -4595,7 +4614,7 @@ void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages,
struct mem_cgroup *memcg = mem_cgroup_from_css(wb->memcg_css);
struct mem_cgroup *parent;
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
*pdirty = memcg_page_state(memcg, NR_FILE_DIRTY);
*pwriteback = memcg_page_state(memcg, NR_WRITEBACK);
@@ -6610,7 +6629,7 @@ static int memory_numa_stat_show(struct seq_file *m, void *v)
int i;
struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
for (i = 0; i < ARRAY_SIZE(memory_stats); i++) {
int nid;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c7c149cb8d66..457a18921fda 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2923,7 +2923,7 @@ static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc)
* Flush the memory cgroup stats, so that we read accurate per-memcg
* lruvec stats for heuristics.
*/
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
/*
* Determine the scan balance between anon and file LRUs.
diff --git a/mm/workingset.c b/mm/workingset.c
index da58a26d0d4d..affb8699e58d 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -520,7 +520,7 @@ void workingset_refault(struct folio *folio, void *shadow)
}
/* Flush stats (and potentially sleep) before holding RCU read lock */
- mem_cgroup_flush_stats_ratelimited();
+ mem_cgroup_try_flush_stats_ratelimited();
rcu_read_lock();
@@ -664,7 +664,7 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
struct lruvec *lruvec;
int i;
- mem_cgroup_flush_stats();
+ mem_cgroup_try_flush_stats();
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,
--
2.42.0.rc2.253.gd59a3bf2b4-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 2/4] mm: memcg: add a helper for non-unified stats flushing
2023-08-28 23:33 [PATCH v2 0/4] memcg: non-unified flushing for userspace stats Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 1/4] mm: memcg: properly name and document unified stats flushing Yosry Ahmed
@ 2023-08-28 23:33 ` Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 3/4] mm: memcg: let non-unified root stats flushes help unified flushes Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 4/4] mm: memcg: use non-unified stats flushing for userspace reads Yosry Ahmed
3 siblings, 0 replies; 5+ messages in thread
From: Yosry Ahmed @ 2023-08-28 23:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Ivan Babrou, Tejun Heo, Michal Koutný,
Waiman Long, linux-mm, cgroups, linux-kernel, Yosry Ahmed
Some contexts flush memcg stats outside of unified flushing, directly
using cgroup_rstat_flush(). Add a helper for non-unified flushing, a
counterpart for do_unified_stats_flush(), and use it in those contexts,
as well as in do_unified_stats_flush() itself.
This abstracts the rstat API and makes it easy to introduce
modifications to either unified or non-unified flushing functions
without changing callers.
No functional change intended.
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
mm/memcontrol.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c6150ea54d48..90f08b35fa77 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -639,6 +639,17 @@ static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
}
}
+/*
+ * do_stats_flush - do a flush of the memory cgroup statistics
+ * @memcg: memory cgroup to flush
+ *
+ * Only flushes the subtree of @memcg, does not skip under any conditions.
+ */
+static void do_stats_flush(struct mem_cgroup *memcg)
+{
+ cgroup_rstat_flush(memcg->css.cgroup);
+}
+
/*
* do_unified_stats_flush - do a unified flush of memory cgroup statistics
*
@@ -656,7 +667,7 @@ static void do_unified_stats_flush(void)
WRITE_ONCE(flush_next_time, jiffies_64 + 2*FLUSH_TIME);
- cgroup_rstat_flush(root_mem_cgroup->css.cgroup);
+ do_stats_flush(root_mem_cgroup);
atomic_set(&stats_flush_threshold, 0);
atomic_set(&stats_flush_ongoing, 0);
@@ -7790,7 +7801,7 @@ bool obj_cgroup_may_zswap(struct obj_cgroup *objcg)
break;
}
- cgroup_rstat_flush(memcg->css.cgroup);
+ do_stats_flush(memcg);
pages = memcg_page_state(memcg, MEMCG_ZSWAP_B) / PAGE_SIZE;
if (pages < max)
continue;
@@ -7855,8 +7866,10 @@ void obj_cgroup_uncharge_zswap(struct obj_cgroup *objcg, size_t size)
static u64 zswap_current_read(struct cgroup_subsys_state *css,
struct cftype *cft)
{
- cgroup_rstat_flush(css->cgroup);
- return memcg_page_state(mem_cgroup_from_css(css), MEMCG_ZSWAP_B);
+ struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+
+ do_stats_flush(memcg);
+ return memcg_page_state(memcg, MEMCG_ZSWAP_B);
}
static int zswap_max_show(struct seq_file *m, void *v)
--
2.42.0.rc2.253.gd59a3bf2b4-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 3/4] mm: memcg: let non-unified root stats flushes help unified flushes
2023-08-28 23:33 [PATCH v2 0/4] memcg: non-unified flushing for userspace stats Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 1/4] mm: memcg: properly name and document unified stats flushing Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 2/4] mm: memcg: add a helper for non-unified " Yosry Ahmed
@ 2023-08-28 23:33 ` Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 4/4] mm: memcg: use non-unified stats flushing for userspace reads Yosry Ahmed
3 siblings, 0 replies; 5+ messages in thread
From: Yosry Ahmed @ 2023-08-28 23:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Ivan Babrou, Tejun Heo, Michal Koutný,
Waiman Long, linux-mm, cgroups, linux-kernel, Yosry Ahmed
Unified flushing of memcg stats keeps track of the magnitude of pending
updates, and only allows a flush if that magnitude exceeds a threshold.
It also keeps track of the time at which ratelimited flushing should be
allowed as flush_next_time.
A non-unified flush on the root memcg has the same effect as a unified
flush, so let it help unified flushing by resetting pending updates and
kicking flush_next_time forward. Move the logic into the common
do_stats_flush() helper, and do it for all root flushes, unified or
not.
There is a subtle change here, we reset stats_flush_threshold before a
flush rather than after a flush. This probably okay because:
(a) For flushers: only unified flushers check stats_flush_threshold, and
those flushers skip anyway if there is another unified flush ongoing.
Having them also skip if there is an ongoing non-unified root flush is
actually more consistent.
(b) For updaters: Resetting stats_flush_threshold early may lead to more
atomic updates of stats_flush_threshold, as we start updating it
earlier. This should not be significant in practice because we stop
updating stats_flush_threshold when it reaches the threshold anyway. If
we start early and stop early, the number of atomic updates remain the
same. The only difference is the scenario where we reset
stats_flush_threshold early, start doing atomic updates early, and then
the periodic flusher kicks in before we reach the threshold. In this
case, we will have done more atomic updates. However, since the
threshold wasn't reached, then we did not do a lot of updates anyway.
Suggested-by: Michal Koutný <mkoutny@suse.com>
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
mm/memcontrol.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 90f08b35fa77..f3716478bf4e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -647,6 +647,11 @@ static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
*/
static void do_stats_flush(struct mem_cgroup *memcg)
{
+ /* for unified flushing, root non-unified flushing can help as well */
+ if (mem_cgroup_is_root(memcg)) {
+ WRITE_ONCE(flush_next_time, jiffies_64 + 2*FLUSH_TIME);
+ atomic_set(&stats_flush_threshold, 0);
+ }
cgroup_rstat_flush(memcg->css.cgroup);
}
@@ -665,11 +670,7 @@ static void do_unified_stats_flush(void)
atomic_xchg(&stats_flush_ongoing, 1))
return;
- WRITE_ONCE(flush_next_time, jiffies_64 + 2*FLUSH_TIME);
-
do_stats_flush(root_mem_cgroup);
-
- atomic_set(&stats_flush_threshold, 0);
atomic_set(&stats_flush_ongoing, 0);
}
--
2.42.0.rc2.253.gd59a3bf2b4-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 4/4] mm: memcg: use non-unified stats flushing for userspace reads
2023-08-28 23:33 [PATCH v2 0/4] memcg: non-unified flushing for userspace stats Yosry Ahmed
` (2 preceding siblings ...)
2023-08-28 23:33 ` [PATCH v2 3/4] mm: memcg: let non-unified root stats flushes help unified flushes Yosry Ahmed
@ 2023-08-28 23:33 ` Yosry Ahmed
3 siblings, 0 replies; 5+ messages in thread
From: Yosry Ahmed @ 2023-08-28 23:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Shakeel Butt,
Muchun Song, Ivan Babrou, Tejun Heo, Michal Koutný,
Waiman Long, linux-mm, cgroups, linux-kernel, Yosry Ahmed
Unified flushing allows for great concurrency for paths that attempt to
flush the stats, at the expense of potential staleness and a single
flusher paying the extra cost of flushing the full tree.
This tradeoff makes sense for in-kernel flushers that may observe high
concurrency (e.g. reclaim, refault). For userspace readers, stale stats
may be unexpected and problematic, especially when such stats are used
for critical paths such as userspace OOM handling. Additionally, a
userspace reader will occasionally pay the cost of flushing the entire
hierarchy, which also causes problems in some cases [1].
Opt userspace reads out of unified flushing. This makes the cost of
reading the stats more predictable (proportional to the size of the
subtree), as well as the freshness of the stats. Since userspace readers
are not expected to have similar concurrency to in-kernel flushers,
serializing them among themselves and among in-kernel flushers should be
okay.
Note that this may make the worst case latency for reading stats worse.
Flushers may give up cgroup_rstat_lock and sleep, causing the number of
waiters for the spinlock theoritically unbounded. A reader may grab the
lock and do some work, give it up, sleep, and then wait for a long time
before acquiring it again and continuing. This is only possible if there
is high concurrency among processes reading stats of different parts of
the hierarchy, such that they are not helping each other out. Other
stats interfaces such as cpu.stat have the same theoritical problem, so
this is unlikely to be a problem in practice. If it is, we can introduce
a mutex in the stats reading path to guard against concurrent readers
competing for the lock. We have similar protection for unified flushing,
except that concurrent flushers skip instead of waiting.
An alternative is to remove flushing from the stats reading path
completely, and rely on the periodic flusher. This should be accompanied
by making the periodic flushing period tunable, and providing an
interface for userspace to force a flush, following a similar model to
/proc/vmstat. However, such a change will be hard to reverse if the
implementation needs to be changed because:
- The cost of reading stats will be very cheap and we won't be able to
take that back easily.
- There are user-visible interfaces involved.
Hence, let's go with the change that's most reversible first. If
problems arise, we can add a mutex in the stats reading path as
described above, or follow the more user-visible approach.
This was tested on a machine with 256 cpus by running a synthetic test
The script that creates 50 top-level cgroups, each with 5 children (250
leaf cgroups). Each leaf cgroup has 10 processes running that allocate
memory beyond the cgroup limit, invoking reclaim (which is an in-kernel
unified flusher). Concurrently, one thread is spawned per-cgroup to read
the stats every second (including root, top-level, and leaf cgroups --
so total 251 threads). No regressions were observed in the total running
time; which means that non-unified userspace readers are not slowing
down in-kernel unified flushers:
Base (mm-unstable):
real 0m18.228s
user 0m9.463s
sys 60m15.879s
real 0m20.828s
user 0m8.535s
sys 70m12.364s
real 0m19.789s
user 0m9.177s
sys 66m10.798s
With this patch:
real 0m19.632s
user 0m8.608s
sys 64m23.483s
real 0m18.463s
user 0m7.465s
sys 60m34.089s
real 0m20.309s
user 0m7.754s
sys 68m2.392s
Additionally, the average latency for reading stats went down up to
8 times when reading stats of leaf cgroups in the script, as we only
have to flush the cgroup(s) being read.
[1]https://lore.kernel.org/lkml/CABWYdi0c6__rh-K7dcM_pkf9BJdTRtAU08M43KO9ME4-dsgfoQ@mail.gmail.com/
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
---
mm/memcontrol.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index f3716478bf4e..8bfb0e3395ce 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1607,7 +1607,7 @@ static void memcg_stat_format(struct mem_cgroup *memcg, struct seq_buf *s)
*
* Current memory state:
*/
- mem_cgroup_try_flush_stats();
+ do_stats_flush(memcg);
for (i = 0; i < ARRAY_SIZE(memory_stats); i++) {
u64 size;
@@ -4049,7 +4049,7 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v)
int nid;
struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
- mem_cgroup_try_flush_stats();
+ do_stats_flush(memcg);
for (stat = stats; stat < stats + ARRAY_SIZE(stats); stat++) {
seq_printf(m, "%s=%lu", stat->name,
@@ -4124,7 +4124,7 @@ static void memcg1_stat_format(struct mem_cgroup *memcg, struct seq_buf *s)
BUILD_BUG_ON(ARRAY_SIZE(memcg1_stat_names) != ARRAY_SIZE(memcg1_stats));
- mem_cgroup_try_flush_stats();
+ do_stats_flush(memcg);
for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
unsigned long nr;
@@ -4626,7 +4626,7 @@ void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages,
struct mem_cgroup *memcg = mem_cgroup_from_css(wb->memcg_css);
struct mem_cgroup *parent;
- mem_cgroup_try_flush_stats();
+ do_stats_flush(memcg);
*pdirty = memcg_page_state(memcg, NR_FILE_DIRTY);
*pwriteback = memcg_page_state(memcg, NR_WRITEBACK);
@@ -6641,7 +6641,7 @@ static int memory_numa_stat_show(struct seq_file *m, void *v)
int i;
struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
- mem_cgroup_try_flush_stats();
+ do_stats_flush(memcg);
for (i = 0; i < ARRAY_SIZE(memory_stats); i++) {
int nid;
--
2.42.0.rc2.253.gd59a3bf2b4-goog
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-08-28 23:33 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-28 23:33 [PATCH v2 0/4] memcg: non-unified flushing for userspace stats Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 1/4] mm: memcg: properly name and document unified stats flushing Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 2/4] mm: memcg: add a helper for non-unified " Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 3/4] mm: memcg: let non-unified root stats flushes help unified flushes Yosry Ahmed
2023-08-28 23:33 ` [PATCH v2 4/4] mm: memcg: use non-unified stats flushing for userspace reads Yosry Ahmed
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox