memcg: add per-memcg vmalloc stat
Subsystems (5)
PATCH v4 1/1 memcg: add per-memcg vmalloc stat
The kvmalloc* allocation functions can fallback to vmalloc allocations and more often on long running machines. In addition the kernel does have __GFP_ACCOUNT kvmalloc* calls. So, often on long running machines, the memory.stat does not tell the complete picture which type of memory is charged to the memcg. So add a per-memcg vmalloc stat.
---
Changes since v3:
- Removed area->page[0] checks and moved to page by page accounting as suggested by Michal
Changes since v2:
- remove cast, per Muchun
- add area->page[0] check, per Michal
Changes since v1:
- page_memcg() within rcu lock as suggested by Muchun.
Documentation/admin-guide/cgroup-v2.rst | 3 +++ include/linux/memcontrol.h | 21 +++++++++++++++++++++ mm/memcontrol.c | 1 + mm/vmalloc.c | 13 +++++++++++-- 4 files changed, 36 insertions(+), 2 deletions(-)
Documentation/admin-guide/cgroup-v2.rst +3 -0
@@ -1314,6 +1314,9 @@ PAGE_SIZE multiple when read back. sock (npn) Amount of memory used in network transmission buffers + vmalloc (npn) + Amount of memory used for vmap backed memory. + shmem Amount of cached filesystem data that is swap-backed, such as tmpfs, shm segments, shared anonymous mmap()s
include/linux/memcontrol.h +21 -0
@@ -33,6 +33,7 @@ enum memcg_stat_item {MEMCG_SWAP =NR_VM_NODE_STAT_ITEMS ,MEMCG_SOCK ,MEMCG_PERCPU_B , +MEMCG_VMALLOC , MEMCG_NR_STAT, };
@@ -944,6 +945,21 @@ static inline void mod_memcg_state(struct mem_cgroup *memcg,local_irq_restore (flags); } +static inline void mod_memcg_page_state (struct page *page, +int idx,int val) +{ +struct mem_cgroup *memcg; + +if (mem_cgroup_disabled ()) +return ; + +rcu_read_lock (); + memcg =page_memcg (page); +if (memcg) +mod_memcg_state (memcg, idx, val); +rcu_read_unlock (); +} +static inline unsigned long memcg_page_state (struct mem_cgroup *memcg,int idx) {return READ_ONCE (memcg->vmstats.state[idx]);
@@ -1399,6 +1415,11 @@ static inline void mod_memcg_state(struct mem_cgroup *memcg, { } +static inline void mod_memcg_page_state (struct page *page, +int idx,int val) +{ +} +static inline unsigned long memcg_page_state (struct mem_cgroup *memcg,int idx) {return 0 ;
mm/memcontrol.c +1 -0
@@ -1375,6 +1375,7 @@ static const struct memory_stat memory_stats[] = { { "pagetables", NR_PAGETABLE }, { "percpu", MEMCG_PERCPU_B }, { "sock", MEMCG_SOCK }, + { "vmalloc", MEMCG_VMALLOC }, { "shmem", NR_SHMEM }, { "file_mapped", NR_FILE_MAPPED }, { "file_dirty", NR_FILE_DIRTY },
mm/vmalloc.c +11 -2
@@ -31,6 +31,7 @@#include <linux/kmemleak.h> #include <linux/atomic.h> #include <linux/compiler.h> +#include <linux/memcontrol.h> #include <linux/llist.h> #include <linux/bitops.h> #include <linux/rbtree_augmented.h>
@@ -2624,12 +2625,13 @@ static void __vunmap(const void *addr, int deallocate_pages)if (deallocate_pages) {unsigned int page_order =vm_area_page_order (area); -int i; +int i, step =1U << page_order; -for (i =0 ; i < area->nr_pages; i +=1U << page_order) { +for (i =0 ; i < area->nr_pages; i += step) {struct page *page = area->pages[i];BUG_ON (!page); +mod_memcg_page_state (page,MEMCG_VMALLOC , -step);__free_pages (page, page_order);cond_resched (); }
@@ -2964,6 +2966,13 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, page_order, nr_small_pages, area->pages);atomic_long_add (area->nr_pages, &nr_vmalloc_pages); +if (gfp_mask & __GFP_ACCOUNT) { +int i, step =1U << page_order; + +for (i =0 ; i < area->nr_pages; i += step) +mod_memcg_page_state (area->pages[i],MEMCG_VMALLOC , + step); + }/* * If not enough pages were obtained to accomplish an
Signature · 1 line
2.34.1.448.ga2b2bfdf31-goog
Quoted 9 lines · Shakeel Butt
The kvmalloc* allocation functions can fallback to vmalloc allocations and more often on long running machines. In addition the kernel does have
__GFP_ACCOUNTkvmalloc* calls. So, often on long running machines, the memory.stat does not tell the complete picture which type of memory is charged to the memcg. So add a per-memcg vmalloc stat.Signed-off-by Shakeel Butt <[email protected]>Reviewed-by Muchun Song <[email protected]>Acked-by Roman Gushchin <[email protected]>
Thanks!
Quoted 135 lines
---
Changes since v3:
- Removed area->page[0] checks and moved to page by page accounting as suggested by MichalChanges since v2:
- remove cast, per Muchun
- add area->page[0] check, per MichalChanges since v1:
-page_memcg()within rcu lock as suggested by Muchun.Documentation/admin-guide/cgroup-v2.rst | 3 +++ include/linux/memcontrol.h | 21 +++++++++++++++++++++ mm/memcontrol.c | 1 + mm/vmalloc.c | 13 +++++++++++-- 4 files changed, 36 insertions(+), 2 deletions(-)Documentation/admin-guide/cgroup-v2.rst +3
-0@@ -1314,6 +1314,9 @@ PAGE_SIZE multiple when read back. sock (npn) Amount of memory used in network transmission buffers + vmalloc (npn) + Amount of memory used for vmap backed memory. + shmem Amount of cached filesystem data that is swap-backed, such as tmpfs, shm segments, shared anonymous mmap()sinclude/linux/memcontrol.h +21
-0@@ -33,6 +33,7 @@ enum memcg_stat_item {MEMCG_SWAP =NR_VM_NODE_STAT_ITEMS ,MEMCG_SOCK ,MEMCG_PERCPU_B , +MEMCG_VMALLOC , MEMCG_NR_STAT, };@@ -944,6 +945,21 @@ static inline void mod_memcg_state(struct mem_cgroup *memcg,local_irq_restore (flags); } +static inline void mod_memcg_page_state (struct page *page, +int idx,int val) +{ +struct mem_cgroup *memcg; + +if (mem_cgroup_disabled ()) +return ; + +rcu_read_lock (); + memcg =page_memcg (page); +if (memcg) +mod_memcg_state (memcg, idx, val); +rcu_read_unlock (); +} +static inline unsigned long memcg_page_state (struct mem_cgroup *memcg,int idx) {return READ_ONCE (memcg->vmstats.state[idx]);@@ -1399,6 +1415,11 @@ static inline void mod_memcg_state(struct mem_cgroup *memcg, { } +static inline void mod_memcg_page_state (struct page *page, +int idx,int val) +{ +} +static inline unsigned long memcg_page_state (struct mem_cgroup *memcg,int idx) {return 0 ;mm/memcontrol.c +1
-0@@ -1375,6 +1375,7 @@ static const struct memory_stat memory_stats[] = { { "pagetables", NR_PAGETABLE }, { "percpu", MEMCG_PERCPU_B }, { "sock", MEMCG_SOCK }, + { "vmalloc", MEMCG_VMALLOC }, { "shmem", NR_SHMEM }, { "file_mapped", NR_FILE_MAPPED }, { "file_dirty", NR_FILE_DIRTY },mm/vmalloc.c +11
-2@@ -31,6 +31,7 @@#include <linux/kmemleak.h> #include <linux/atomic.h> #include <linux/compiler.h> +#include <linux/memcontrol.h> #include <linux/llist.h> #include <linux/bitops.h> #include <linux/rbtree_augmented.h> @@ -2624,12 +2625,13 @@ static void __vunmap(const void *addr, int deallocate_pages)if (deallocate_pages) {unsigned int page_order =vm_area_page_order (area); -int i; +int i, step =1U << page_order; -for (i =0 ; i < area->nr_pages; i +=1U << page_order) { +for (i =0 ; i < area->nr_pages; i += step) {struct page *page = area->pages[i];BUG_ON (!page); +mod_memcg_page_state (page,MEMCG_VMALLOC , -step);__free_pages (page, page_order);cond_resched (); }@@ -2964,6 +2966,13 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, page_order, nr_small_pages, area->pages);atomic_long_add (area->nr_pages, &nr_vmalloc_pages); +if (gfp_mask & __GFP_ACCOUNT) { +int i, step =1U << page_order; + +for (i =0 ; i < area->nr_pages; i += step) +mod_memcg_page_state (area->pages[i],MEMCG_VMALLOC , + step); + }/* * If not enough pages were obtained to accomplish an Signature · 1 line
2.34.1.448.ga2b2bfdf31-goog
Signature · 2 lines
Michal Hocko SUSE Labs