[PATCH v6 2/2] mm: hugetlb: proc: add HugetlbPages field to /proc/PID/status

From: Naoya Horiguchi
Date: Thu Sep 17 2015 - 05:12:40 EST


Currently there's no easy way to get per-process usage of hugetlb pages, which
is inconvenient because userspace applications which use hugetlb typically want
to control their processes on the basis of how much memory (including hugetlb)
they use. So this patch simply provides easy access to the info via
/proc/PID/status.

Signed-off-by: Naoya Horiguchi <n-horiguchi@xxxxxxxxxxxxx>
Acked-by: Joern Engel <joern@xxxxxxxxx>
Acked-by: David Rientjes <rientjes@xxxxxxxxxx>
---
v5 -> v6:
- drop showing per-pagesize info

v4 -> v5:
- add (struct hugetlb_usage *) to struct mm_struct
- use %lu instead of %d for seq_printf()
- introduce hugetlb_fork

v3 -> v4:
- rename field (VmHugetlbRSS is not the best name)
- introduce struct hugetlb_usage in struct mm_struct (no invasion to struct
mm_rss_stat)
- introduce hugetlb_report_usage()
- merged documentation update

v2 -> v3:
- use inline functions instead of macros for !CONFIG_HUGETLB_PAGE
---
Documentation/filesystems/proc.txt | 2 ++
fs/proc/task_mmu.c | 1 +
include/linux/hugetlb.h | 19 +++++++++++++++++++
include/linux/mm_types.h | 3 +++
mm/hugetlb.c | 9 +++++++++
mm/rmap.c | 4 +++-
6 files changed, 37 insertions(+), 1 deletion(-)

diff --git v4.3-rc1/Documentation/filesystems/proc.txt v4.3-rc1_patched/Documentation/filesystems/proc.txt
index b9467d91052a..da29faaf685e 100644
--- v4.3-rc1/Documentation/filesystems/proc.txt
+++ v4.3-rc1_patched/Documentation/filesystems/proc.txt
@@ -174,6 +174,7 @@ For example, to get the status information of a process, all you have to do is
VmLib: 1412 kB
VmPTE: 20 kb
VmSwap: 0 kB
+ HugetlbPages: 0 kB
Threads: 1
SigQ: 0/28578
SigPnd: 0000000000000000
@@ -237,6 +238,7 @@ Table 1-2: Contents of the status files (as of 4.1)
VmPTE size of page table entries
VmPMD size of second level page tables
VmSwap size of swap usage (the number of referred swapents)
+ HugetlbPages size of hugetlb memory portions
Threads number of threads
SigQ number of signals queued/max. number for queue
SigPnd bitmap of pending signals for the thread
diff --git v4.3-rc1/fs/proc/task_mmu.c v4.3-rc1_patched/fs/proc/task_mmu.c
index 22c02917f265..bd167675a06f 100644
--- v4.3-rc1/fs/proc/task_mmu.c
+++ v4.3-rc1_patched/fs/proc/task_mmu.c
@@ -70,6 +70,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
ptes >> 10,
pmds >> 10,
swap << (PAGE_SHIFT-10));
+ hugetlb_report_usage(m, mm);
}

unsigned long task_vsize(struct mm_struct *mm)
diff --git v4.3-rc1/include/linux/hugetlb.h v4.3-rc1_patched/include/linux/hugetlb.h
index 5e35379f58a5..685c262e0be8 100644
--- v4.3-rc1/include/linux/hugetlb.h
+++ v4.3-rc1_patched/include/linux/hugetlb.h
@@ -483,6 +483,17 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
#define hugepages_supported() (HPAGE_SHIFT != 0)
#endif

+void hugetlb_report_usage(struct seq_file *m, struct mm_struct *mm);
+
+static inline void hugetlb_count_add(long l, struct mm_struct *mm)
+{
+ atomic_long_add(l, &mm->hugetlb_usage);
+}
+
+static inline void hugetlb_count_sub(long l, struct mm_struct *mm)
+{
+ atomic_long_sub(l, &mm->hugetlb_usage);
+}
#else /* CONFIG_HUGETLB_PAGE */
struct hstate {};
#define alloc_huge_page(v, a, r) NULL
@@ -519,6 +530,14 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
{
return &mm->page_table_lock;
}
+
+static inline void hugetlb_report_usage(struct seq_file *f, struct mm_struct *m)
+{
+}
+
+static inline void hugetlb_count_sub(long l, struct mm_struct *mm)
+{
+}
#endif /* CONFIG_HUGETLB_PAGE */

static inline spinlock_t *huge_pte_lock(struct hstate *h,
diff --git v4.3-rc1/include/linux/mm_types.h v4.3-rc1_patched/include/linux/mm_types.h
index 3d6baa7d4534..0a85da25a822 100644
--- v4.3-rc1/include/linux/mm_types.h
+++ v4.3-rc1_patched/include/linux/mm_types.h
@@ -486,6 +486,9 @@ struct mm_struct {
/* address of the bounds directory */
void __user *bd_addr;
#endif
+#ifdef CONFIG_HUGETLB_PAGE
+ atomic_long_t hugetlb_usage;
+#endif
};

static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git v4.3-rc1/mm/hugetlb.c v4.3-rc1_patched/mm/hugetlb.c
index 999fb0aef8f1..444a55de3c4a 100644
--- v4.3-rc1/mm/hugetlb.c
+++ v4.3-rc1_patched/mm/hugetlb.c
@@ -2790,6 +2790,12 @@ void hugetlb_show_meminfo(void)
1UL << (huge_page_order(h) + PAGE_SHIFT - 10));
}

+void hugetlb_report_usage(struct seq_file *m, struct mm_struct *mm)
+{
+ seq_printf(m, "HugetlbPages:\t%8lu kB\n",
+ atomic_long_read(&mm->hugetlb_usage) << (PAGE_SHIFT - 10));
+}
+
/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
unsigned long hugetlb_total_pages(void)
{
@@ -3025,6 +3031,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
get_page(ptepage);
page_dup_rmap(ptepage);
set_huge_pte_at(dst, addr, dst_pte, entry);
+ hugetlb_count_add(pages_per_huge_page(h), dst);
}
spin_unlock(src_ptl);
spin_unlock(dst_ptl);
@@ -3105,6 +3112,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
if (huge_pte_dirty(pte))
set_page_dirty(page);

+ hugetlb_count_sub(pages_per_huge_page(h), mm);
page_remove_rmap(page);
force_flush = !__tlb_remove_page(tlb, page);
if (force_flush) {
@@ -3501,6 +3509,7 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
&& (vma->vm_flags & VM_SHARED)));
set_huge_pte_at(mm, address, ptep, new_pte);

+ hugetlb_count_add(pages_per_huge_page(h), mm);
if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) {
/* Optimization, do the COW without a second fault */
ret = hugetlb_cow(mm, vma, address, ptep, new_pte, page, ptl);
diff --git v4.3-rc1/mm/rmap.c v4.3-rc1_patched/mm/rmap.c
index f5b5c1f3dcd7..d40e7aefb888 100644
--- v4.3-rc1/mm/rmap.c
+++ v4.3-rc1_patched/mm/rmap.c
@@ -1352,7 +1352,9 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
update_hiwater_rss(mm);

if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) {
- if (!PageHuge(page)) {
+ if (PageHuge(page)) {
+ hugetlb_count_sub(1 << compound_order(page), mm);
+ } else {
if (PageAnon(page))
dec_mm_counter(mm, MM_ANONPAGES);
else
--
2.4.3