summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorYafang Shao <laoar.shao@gmail.com>2019-07-16 19:26:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-16 22:23:21 -0400
commit766a4c19d880887c457811b86f1f68525e416965 (patch)
treed249e91205876cc0126f1765cd71de40958ddfd2 /mm
parentf1549cb5ab2bd04cb370502b720268f610e21baa (diff)
mm/memcontrol.c: keep local VM counters in sync with the hierarchical ones
After commit 815744d75152 ("mm: memcontrol: don't batch updates of local VM stats and events"), the local VM counter are not in sync with the hierarchical ones. Below is one example in a leaf memcg on my server (with 8 CPUs): inactive_file 3567570944 total_inactive_file 3568029696 We find that the deviation is very great because the 'val' in __mod_memcg_state() is in pages while the effective value in memcg_stat_show() is in bytes. So the maximum of this deviation between local VM stats and total VM stats can be (32 * number_of_cpu * PAGE_SIZE), that may be an unacceptably great value. We should keep the local VM stats in sync with the total stats. In order to keep this behavior the same across counters, this patch updates __mod_lruvec_state() and __count_memcg_events() as well. Link: http://lkml.kernel.org/r/1562851979-10610-1-git-send-email-laoar.shao@gmail.com Signed-off-by: Yafang Shao <laoar.shao@gmail.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: Vladimir Davydov <vdavydov.dev@gmail.com> Cc: Yafang Shao <shaoyafang@didiglobal.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 249671873aa9..cdbb7a84cb6e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -695,12 +695,15 @@ void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val)
695 if (mem_cgroup_disabled()) 695 if (mem_cgroup_disabled())
696 return; 696 return;
697 697
698 __this_cpu_add(memcg->vmstats_local->stat[idx], val);
699
700 x = val + __this_cpu_read(memcg->vmstats_percpu->stat[idx]); 698 x = val + __this_cpu_read(memcg->vmstats_percpu->stat[idx]);
701 if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) { 699 if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
702 struct mem_cgroup *mi; 700 struct mem_cgroup *mi;
703 701
702 /*
703 * Batch local counters to keep them in sync with
704 * the hierarchical ones.
705 */
706 __this_cpu_add(memcg->vmstats_local->stat[idx], x);
704 for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) 707 for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
705 atomic_long_add(x, &mi->vmstats[idx]); 708 atomic_long_add(x, &mi->vmstats[idx]);
706 x = 0; 709 x = 0;
@@ -749,13 +752,15 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
749 /* Update memcg */ 752 /* Update memcg */
750 __mod_memcg_state(memcg, idx, val); 753 __mod_memcg_state(memcg, idx, val);
751 754
752 /* Update lruvec */
753 __this_cpu_add(pn->lruvec_stat_local->count[idx], val);
754
755 x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]); 755 x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]);
756 if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) { 756 if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
757 struct mem_cgroup_per_node *pi; 757 struct mem_cgroup_per_node *pi;
758 758
759 /*
760 * Batch local counters to keep them in sync with
761 * the hierarchical ones.
762 */
763 __this_cpu_add(pn->lruvec_stat_local->count[idx], x);
759 for (pi = pn; pi; pi = parent_nodeinfo(pi, pgdat->node_id)) 764 for (pi = pn; pi; pi = parent_nodeinfo(pi, pgdat->node_id))
760 atomic_long_add(x, &pi->lruvec_stat[idx]); 765 atomic_long_add(x, &pi->lruvec_stat[idx]);
761 x = 0; 766 x = 0;
@@ -777,12 +782,15 @@ void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx,
777 if (mem_cgroup_disabled()) 782 if (mem_cgroup_disabled())
778 return; 783 return;
779 784
780 __this_cpu_add(memcg->vmstats_local->events[idx], count);
781
782 x = count + __this_cpu_read(memcg->vmstats_percpu->events[idx]); 785 x = count + __this_cpu_read(memcg->vmstats_percpu->events[idx]);
783 if (unlikely(x > MEMCG_CHARGE_BATCH)) { 786 if (unlikely(x > MEMCG_CHARGE_BATCH)) {
784 struct mem_cgroup *mi; 787 struct mem_cgroup *mi;
785 788
789 /*
790 * Batch local counters to keep them in sync with
791 * the hierarchical ones.
792 */
793 __this_cpu_add(memcg->vmstats_local->events[idx], x);
786 for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) 794 for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
787 atomic_long_add(x, &mi->vmevents[idx]); 795 atomic_long_add(x, &mi->vmevents[idx]);
788 x = 0; 796 x = 0;