History

mm: memcontrol: make cgroup stats and events query API explicitly local

Patch series "mm: memcontrol: memory.stat cost & correctness". The cgroup memory.stat file holds recursive statistics for the entire subtree. The current implementation does this tree walk on-demand whenever the file is read. This is giving us problems in production. 1. The cost of aggregating the statistics on-demand is high. A lot of system service cgroups are mostly idle and their stats don't change between reads, yet we always have to check them. There are also always some lazily-dying cgroups sitting around that are pinned by a handful of remaining page cache; the same applies to them. In an application that periodically monitors memory.stat in our fleet, we have seen the aggregation consume up to 5% CPU time. 2. When cgroups die and disappear from the cgroup tree, so do their accumulated vm events. The result is that the event counters at higher-level cgroups can go backwards and confuse some of our automation, let alone people looking at the graphs over time. To address both issues, this patch series changes the stat implementation to spill counts upwards when the counters change. The upward spilling is batched using the existing per-cpu cache. In a sparse file stress test with 5 level cgroup nesting, the additional cost of the flushing was negligible (a little under 1% of CPU at 100% CPU utilization, compared to the 5% of reading memory.stat during regular operation). This patch (of 4): memcg_page_state(), lruvec_page_state(), memcg_sum_events() are currently returning the state of the local memcg or lruvec, not the recursive state. In practice there is a demand for both versions, although the callers that want the recursive counts currently sum them up by hand. Per default, cgroups are considered recursive entities and generally we expect more users of the recursive counters, with the local counts being special cases. To reflect that in the name, add a _local suffix to the current implementations. The following patch will re-incarnate these functions with recursive semantics, but with an O(1) implementation. [hannes@cmpxchg.org: fix bisection hole] Link: http://lkml.kernel.org/r/20190417160347.GC23013@cmpxchg.org Link: http://lkml.kernel.org/r/20190412151507.2769-2-hannes@cmpxchg.org Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Reviewed-by: Shakeel Butt <shakeelb@google.com> Reviewed-by: Roman Gushchin <guro@fb.com> Cc: Michal Hocko <mhocko@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Johannes Weiner committed 7 years ago

Commit 205b20c1 parent 6a024334 files · +36 −33Browse files

Showing the changes to include/linux (1 of 4 files). Show all

Unified · Split

include/linux/memcontrol.h+8−8
@@ -554,8 +554,8 @@ void unlock_page_memcg(struct page *page); · 553 unmodified lines
554 * idx can be of type enum memcg_stat_item or node_stat_item.554 * idx can be of type enum memcg_stat_item or node_stat_item.
555 * Keep in sync with memcg_exact_page_state().555 * Keep in sync with memcg_exact_page_state().
556 */556 */
557static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,557static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg,
558 int idx)558 int idx)
559{559{
560 long x = atomic_long_read(&memcg->vmstats[idx]);560 long x = atomic_long_read(&memcg->vmstats[idx]);
561#ifdef CONFIG_SMP561#ifdef CONFIG_SMP
@@ -624,8 +624,8 @@ static inline void mod_memcg_page_state(struct page *page, · 62 unmodified lines
624 mod_memcg_state(page->mem_cgroup, idx, val);624 mod_memcg_state(page->mem_cgroup, idx, val);
625}625}
626 626
627static inline unsigned long lruvec_page_state(struct lruvec *lruvec,627static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
628 enum node_stat_item idx)628 enum node_stat_item idx)
629{629{
630 struct mem_cgroup_per_node *pn;630 struct mem_cgroup_per_node *pn;
631 long x;631 long x;
@@ -1011,8 +1011,8 @@ static inline void mem_cgroup_print_oom_group(struct mem_cgroup *memcg) · 379 unmodified lines
1011{1011{
1012}1012}
1013 1013
1014static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,1014static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg,
1015 int idx)1015 int idx)
1016{1016{
1017 return 0;1017 return 0;
1018}1018}
@@ -1041,8 +1041,8 @@ static inline void mod_memcg_page_state(struct page *page, · 22 unmodified lines
1041{1041{
1042}1042}
1043 1043
1044static inline unsigned long lruvec_page_state(struct lruvec *lruvec,1044static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
1045 enum node_stat_item idx)1045 enum node_stat_item idx)
1046{1046{
1047 return node_page_state(lruvec_pgdat(lruvec), idx);1047 return node_page_state(lruvec_pgdat(lruvec), idx);
1048}1048}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t