lkml.org 
[lkml]   [2022]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH] memcg: sync flush only if periodic flush is delayed
From
Hi Michal,

On Fri, Mar 11, 2022 at 05:00:51PM +0100, Michal Koutný wrote:
> Hello.

> TL;DR rstats are slow but accurate on reader side. To tackle the
> performance regression no flush seems simpler than this patch.


The term 'simpler' is very subjective here and I would argue this patch
is not that complicated than no flush but I think there is no benefit on
arguing on this as these are not some stable API which can not be
changed later. We can always come back and change based on new findings.

Before going further, I do want to mention the main reason to move to
rstat infrastructure was to decouple the error rate in the stats from
the number of memory cgroups and the number of stat items. So, I will
focus on the error rate in this email.

[...]

> The benefit this was traded for was the greater accuracy, the possible
> error is:
> - before
> - O(nr_cpus * nr_cgroups(subtree) * MEMCG_CHARGE_BATCH) (1)

Please note that (1) is the possible error for each stat item and
without any time bound.

> - after
> O(nr_cpus * MEMCG_CHARGE_BATCH) // sync. flush

The above is across all the stat items.

> or
> O(flush_period * max_cr) // periodic flush only (2)
> // max_cr is per-counter max change rate

And this above one, I am assuming, is for performance critical readers
(workingset_refault introduced by this patch) and flush_period here is 4
seconds. Please correct me if I misunderstood this.


> So we could argue that if the pre-rstat kernels did just fine with the
> error (1), they would not be worse with periodic flush if we can compare
> (1) and (2).

I agree with this assessment but please note that pre-rstat kernels were
not good for machines with large number of CPUs and running large number
of workloads.

[...]

> I'm not sure whether your patch attempts to solve the problem of
> (a) periodic flush getting stuck or (b) limiting error on refault path.
> If it's (a), it should be tackled more systematically (dedicated wq?).
> If it's (b), why not just rely on periodic flush (self answer: (1) and
> (2) comparison is workload dependent).


It is (b) that I am aiming for in this patch. At least (a) was not
happening in the cloudflare experiments. Are you suggesting having a
dedicated high priority wq would solve both (a) and (b)?

> > Now the question: what are the side-effects of this change? The worst
> > that can happen is the refault codepath will see 4sec old lruvec stats
> > and may cause false (or missed) activations of the refaulted page which
> > may under-or-overestimate the workingset size. Though that is not very
> > concerning as the kernel can already miss or do false activations.

> We can't argue what's the effect of periodic only flushing so this
> newly introduced factor would inherit that too. I find it superfluous.


Sorry I didn't get your point. What is superfluous?


> Michal

> [1] This is worth looking at in more detail.


Oh you did some awesome analysis here.

> From the flush condition we have
> cr * Δt = nr_cpus * MEMCG_CHARGE_BATCH
> where Δt is time between flushes and cr is global change rate.

> cr composes of all updates together (corresponds to stats_updates in
> memcg_rstat_updated(), max_cr is change rate per counter)
> cr = Σ cr_i <= nr_counters * max_cr

I don't get the reason of breaking 'cr' into individual stat item or
counter. What is the benefit? We want to keep the error rate decoupled
from the number of counters (or stat items).


> By combining these two we get shortest time between flushes:
> cr * Δt <= nr_counters * max_cr * Δt
> nr_cpus * MEMCG_CHARGE_BATCH <= nr_counters * max_cr * Δt
> Δt >= (nr_cpus * MEMCG_CHARGE_BATCH) / (nr_counters * max_cr)

> We are interested in
> R_amort = flush_work / Δt
> which is
> R_amort <= flush_work * nr_counters * max_cr / (nr_cpus *
> MEMCG_CHARGE_BATCH)

> R_amort: O( nr_cpus * nr_cgroups(subtree) * nr_counters * (nr_counters *
> max_cr) / (nr_cpus * MEMCG_CHARGE_BATCH) )
> R_amort: O( nr_cgroups(subtree) * nr_counters^2 * max_cr) /
> (MEMCG_CHARGE_BATCH) )

> The square looks interesting given there are already tens of counters.
> (As data from Ivan have shown, we can hardly restore the pre-rstat
> performance on the read side even with mere mod_delayed_work().)
> This is what you partially solved with introduction of NR_MEMCG_EVENTS

My main reason behind trying NR_MEMCG_EVENTS was to reduce flush_work by
reducing nr_counters and I don't think nr_counters should have an impact
on Δt.

> but the stats_updates was still sum of all events, so the flush might
> have still triggered too frequently.

> Maybe that would be better long-term approach, splitting into accurate
> and approximate counters and reflect that in the error estimator
> stats_updates.

> Or some other optimization of mem_cgroup_css_rstat_flush().


Thanks for your insights. This is really awesome and good to explore the
long-term approach. Do you have any strong concerns with the currect
patch? I think we should proceed with this and focus more on long-term
approach.

thanks,
Shakeel



\
 
 \ /
  Last update: 2022-03-12 20:08    [W:0.099 / U:0.244 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site