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

mm, memcg: add rss_huge stat to memory.stat

This exports the amount of anonymous transparent hugepages for each
memcg via the new "rss_huge" stat in memory.stat. The units are in
bytes.

This is helpful to determine the hugepage utilization for individual
jobs on the system in comparison to rss and opportunities where
MADV_HUGEPAGE may be helpful.

The amount of anonymous transparent hugepages is also included in "rss"
for backwards compatibility.

Signed-off-by: David Rientjes <rientjes@google.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Rientjes and committed by
Linus Torvalds
b070e65c 70affe45

+29 -11
+3 -1
Documentation/cgroups/memory.txt
··· 480 480 481 481 # per-memory cgroup local status 482 482 cache - # of bytes of page cache memory. 483 - rss - # of bytes of anonymous and swap cache memory. 483 + rss - # of bytes of anonymous and swap cache memory (includes 484 + transparent hugepages). 485 + rss_huge - # of bytes of anonymous transparent hugepages. 484 486 mapped_file - # of bytes of mapped file (includes tmpfs/shmem) 485 487 pgpgin - # of charging events to the memory cgroup. The charging 486 488 event happens each time a page is accounted as either mapped
+26 -10
mm/memcontrol.c
··· 92 92 /* 93 93 * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss. 94 94 */ 95 - MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ 96 - MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ 97 - MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ 98 - MEM_CGROUP_STAT_SWAP, /* # of pages, swapped out */ 95 + MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ 96 + MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ 97 + MEM_CGROUP_STAT_RSS_HUGE, /* # of pages charged as anon huge */ 98 + MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ 99 + MEM_CGROUP_STAT_SWAP, /* # of pages, swapped out */ 99 100 MEM_CGROUP_STAT_NSTATS, 100 101 }; 101 102 102 103 static const char * const mem_cgroup_stat_names[] = { 103 104 "cache", 104 105 "rss", 106 + "rss_huge", 105 107 "mapped_file", 106 108 "swap", 107 109 }; ··· 919 917 } 920 918 921 919 static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, 920 + struct page *page, 922 921 bool anon, int nr_pages) 923 922 { 924 923 preempt_disable(); ··· 933 930 nr_pages); 934 931 else 935 932 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE], 933 + nr_pages); 934 + 935 + if (PageTransHuge(page)) 936 + __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE], 936 937 nr_pages); 937 938 938 939 /* pagein of a big page is an event. So, ignore page size */ ··· 2921 2914 else 2922 2915 anon = false; 2923 2916 2924 - mem_cgroup_charge_statistics(memcg, anon, nr_pages); 2917 + mem_cgroup_charge_statistics(memcg, page, anon, nr_pages); 2925 2918 unlock_page_cgroup(pc); 2926 2919 2927 2920 /* ··· 3715 3708 { 3716 3709 struct page_cgroup *head_pc = lookup_page_cgroup(head); 3717 3710 struct page_cgroup *pc; 3711 + struct mem_cgroup *memcg; 3718 3712 int i; 3719 3713 3720 3714 if (mem_cgroup_disabled()) 3721 3715 return; 3716 + 3717 + memcg = head_pc->mem_cgroup; 3722 3718 for (i = 1; i < HPAGE_PMD_NR; i++) { 3723 3719 pc = head_pc + i; 3724 - pc->mem_cgroup = head_pc->mem_cgroup; 3720 + pc->mem_cgroup = memcg; 3725 3721 smp_wmb();/* see __commit_charge() */ 3726 3722 pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT; 3727 3723 } 3724 + __this_cpu_sub(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE], 3725 + HPAGE_PMD_NR); 3728 3726 } 3729 3727 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 3730 3728 ··· 3785 3773 __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); 3786 3774 preempt_enable(); 3787 3775 } 3788 - mem_cgroup_charge_statistics(from, anon, -nr_pages); 3776 + mem_cgroup_charge_statistics(from, page, anon, -nr_pages); 3789 3777 3790 3778 /* caller should have done css_get */ 3791 3779 pc->mem_cgroup = to; 3792 - mem_cgroup_charge_statistics(to, anon, nr_pages); 3780 + mem_cgroup_charge_statistics(to, page, anon, nr_pages); 3793 3781 move_unlock_mem_cgroup(from, &flags); 3794 3782 ret = 0; 3795 3783 unlock: ··· 4164 4152 break; 4165 4153 } 4166 4154 4167 - mem_cgroup_charge_statistics(memcg, anon, -nr_pages); 4155 + mem_cgroup_charge_statistics(memcg, page, anon, -nr_pages); 4168 4156 4169 4157 ClearPageCgroupUsed(pc); 4170 4158 /* ··· 4514 4502 lock_page_cgroup(pc); 4515 4503 if (PageCgroupUsed(pc)) { 4516 4504 memcg = pc->mem_cgroup; 4517 - mem_cgroup_charge_statistics(memcg, false, -1); 4505 + mem_cgroup_charge_statistics(memcg, oldpage, false, -1); 4518 4506 ClearPageCgroupUsed(pc); 4519 4507 } 4520 4508 unlock_page_cgroup(pc); ··· 5042 5030 return res_counter_read_u64(&memcg->memsw, RES_USAGE); 5043 5031 } 5044 5032 5033 + /* 5034 + * Transparent hugepages are still accounted for in MEM_CGROUP_STAT_RSS 5035 + * as well as in MEM_CGROUP_STAT_RSS_HUGE. 5036 + */ 5045 5037 val = mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_CACHE); 5046 5038 val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_RSS); 5047 5039