Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: memcg: refactor page state unit helpers

Patch series "mm: memcg: fix tracking of pending stats updates values", v2.

While working on adjacent code [1], I realized that the values passed into
memcg_rstat_updated() to keep track of the magnitude of pending updates is
consistent. It is mostly in pages, but sometimes it can be in bytes or
KBs. Fix that.

Patch 1 reworks memcg_page_state_unit() so that we can reuse it in patch 2
to check and normalize the units of state updates.

[1]https://lore.kernel.org/lkml/20230921081057.3440885-1-yosryahmed@google.com/


This patch (of 2):

memcg_page_state_unit() is currently used to identify the unit of a memcg
state item so that all stats in memory.stat are in bytes. However, it
lies about the units of WORKINGSET_* stats. These stats actually
represent pages, but we present them to userspace as a scalar number of
events. In retrospect, maybe those stats should have been memcg "events"
rather than memcg "state".

In preparation for using memcg_page_state_unit() for other purposes that
need to know the truthful units of different stat items, break it down
into two helpers:
- memcg_page_state_unit() retuns the actual unit of the item.
- memcg_page_state_output_unit() returns the unit used for output.

Use the latter instead of the former in memcg_page_state_output() and
lruvec_page_state_output(). While we are at it, let's show cgroup v1 some
love and add memcg_page_state_local_output() for consistency.

No functional change intended.

Link: https://lkml.kernel.org/r/20230922175741.635002-1-yosryahmed@google.com
Link: https://lkml.kernel.org/r/20230922175741.635002-2-yosryahmed@google.com
Signed-off-by: Yosry Ahmed <yosryahmed@google.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeelb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Yosry Ahmed and committed by
Andrew Morton
ff841a06 b7c67206

+37 -15
+37 -15
mm/memcontrol.c
··· 1535 1535 { "workingset_nodereclaim", WORKINGSET_NODERECLAIM }, 1536 1536 }; 1537 1537 1538 - /* Translate stat items to the correct unit for memory.stat output */ 1538 + /* The actual unit of the state item, not the same as the output unit */ 1539 1539 static int memcg_page_state_unit(int item) 1540 1540 { 1541 1541 switch (item) { ··· 1543 1543 case MEMCG_ZSWAP_B: 1544 1544 case NR_SLAB_RECLAIMABLE_B: 1545 1545 case NR_SLAB_UNRECLAIMABLE_B: 1546 - case WORKINGSET_REFAULT_ANON: 1547 - case WORKINGSET_REFAULT_FILE: 1548 - case WORKINGSET_ACTIVATE_ANON: 1549 - case WORKINGSET_ACTIVATE_FILE: 1550 - case WORKINGSET_RESTORE_ANON: 1551 - case WORKINGSET_RESTORE_FILE: 1552 - case WORKINGSET_NODERECLAIM: 1553 1546 return 1; 1554 1547 case NR_KERNEL_STACK_KB: 1555 1548 return SZ_1K; ··· 1551 1558 } 1552 1559 } 1553 1560 1561 + /* Translate stat items to the correct unit for memory.stat output */ 1562 + static int memcg_page_state_output_unit(int item) 1563 + { 1564 + /* 1565 + * Workingset state is actually in pages, but we export it to userspace 1566 + * as a scalar count of events, so special case it here. 1567 + */ 1568 + switch (item) { 1569 + case WORKINGSET_REFAULT_ANON: 1570 + case WORKINGSET_REFAULT_FILE: 1571 + case WORKINGSET_ACTIVATE_ANON: 1572 + case WORKINGSET_ACTIVATE_FILE: 1573 + case WORKINGSET_RESTORE_ANON: 1574 + case WORKINGSET_RESTORE_FILE: 1575 + case WORKINGSET_NODERECLAIM: 1576 + return 1; 1577 + default: 1578 + return memcg_page_state_unit(item); 1579 + } 1580 + } 1581 + 1554 1582 static inline unsigned long memcg_page_state_output(struct mem_cgroup *memcg, 1555 1583 int item) 1556 1584 { 1557 - return memcg_page_state(memcg, item) * memcg_page_state_unit(item); 1585 + return memcg_page_state(memcg, item) * 1586 + memcg_page_state_output_unit(item); 1587 + } 1588 + 1589 + static inline unsigned long memcg_page_state_local_output( 1590 + struct mem_cgroup *memcg, int item) 1591 + { 1592 + return memcg_page_state_local(memcg, item) * 1593 + memcg_page_state_output_unit(item); 1558 1594 } 1559 1595 1560 1596 static void memcg_stat_format(struct mem_cgroup *memcg, struct seq_buf *s) ··· 4135 4113 for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) { 4136 4114 unsigned long nr; 4137 4115 4138 - nr = memcg_page_state_local(memcg, memcg1_stats[i]); 4139 - seq_buf_printf(s, "%s %lu\n", memcg1_stat_names[i], 4140 - nr * memcg_page_state_unit(memcg1_stats[i])); 4116 + nr = memcg_page_state_local_output(memcg, memcg1_stats[i]); 4117 + seq_buf_printf(s, "%s %lu\n", memcg1_stat_names[i], nr); 4141 4118 } 4142 4119 4143 4120 for (i = 0; i < ARRAY_SIZE(memcg1_events); i++) ··· 4162 4141 for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) { 4163 4142 unsigned long nr; 4164 4143 4165 - nr = memcg_page_state(memcg, memcg1_stats[i]); 4144 + nr = memcg_page_state_output(memcg, memcg1_stats[i]); 4166 4145 seq_buf_printf(s, "total_%s %llu\n", memcg1_stat_names[i], 4167 - (u64)nr * memcg_page_state_unit(memcg1_stats[i])); 4146 + (u64)nr); 4168 4147 } 4169 4148 4170 4149 for (i = 0; i < ARRAY_SIZE(memcg1_events); i++) ··· 6646 6625 static inline unsigned long lruvec_page_state_output(struct lruvec *lruvec, 6647 6626 int item) 6648 6627 { 6649 - return lruvec_page_state(lruvec, item) * memcg_page_state_unit(item); 6628 + return lruvec_page_state(lruvec, item) * 6629 + memcg_page_state_output_unit(item); 6650 6630 } 6651 6631 6652 6632 static int memory_numa_stat_show(struct seq_file *m, void *v)