mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCHv2 1/2] proc: mm: export PTE sizes directly in smaps
@ 2017-10-24 10:49 Fan Du
  2017-10-24 10:49 ` [PATCHv2 2/2] Add /proc/PID/{smaps, numa_maps} support for DAX Fan Du
  0 siblings, 1 reply; 3+ messages in thread
From: Fan Du @ 2017-10-24 10:49 UTC (permalink / raw)
  To: akpm, hch, dan.j.williams, dave.hansen; +Cc: linux-kernel, Fan Du

/proc/$pid/smaps has a number of fields that are intended to imply the
kinds of PTEs used to map memory.  "AnonHugePages" obviously tells you
how many PMDs are being used.  "MMUPageSize" along with the "Hugetlb"
fields tells you how many PTEs you have for a huge page.

The current mechanisms work fine when we have one or two page sizes.
But, they start to get a bit muddled when we mix page sizes inside
one VMA.  For instance, the DAX folks were proposing adding a set of
fields like:

	DevicePages:
	DeviceHugePages:
	DeviceGiganticPages:
	DeviceGinormousPages:

to unmuddle things when page sizes get mixed.  That's fine, but
it does require userspace know the mapping from our various
arbitrary names to hardware page sizes on each architecture and
kernel configuration.  That seems rather suboptimal.

What folks really want is to know how much memory is mapped with
each page size.  How about we just do *that* instead?

Patch attached.  Seems harmless enough.  Seems to compile on a
bunch of random architectures.  Makes smaps look like this:

Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
Ptes@4kB:	      32 kB
Ptes@2MB:	    2048 kB

The format I used here should be unlikely to break smaps parsers
unless they're looking for "kB" and now match the 'Ptes@4kB' instead
of the one at the end of the line.

Note: hugetlbfs PTEs are unusual.  We can have more than one "pte_t"
for each hugetlbfs "page".  arm64 has this configuration, and probably
others.  The code should now handle when an hstate's size is not equal
to one of the page table entry sizes.  For instance, it assumes that
hstates between PMD_SIZE and PUD_SIZE are made up of multiple PMDs
and prints them as such.

I've tested this on x86 with normal 4k ptes, anonymous huge pages,
1G hugetlbfs and 2M hugetlbfs pages.

1. I'd like to thank Dan Williams for showing me a mirror as I
   complained about the bozo that introduced 'AnonHugePages'.

[Fan]
Rebase the original patch from Dave Hansen by fixing a couple of compile
issues.

Signed-off-by: Fan Du <fan.du@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@intel.com>
---
 Documentation/filesystems/proc.txt |   6 +++
 fs/proc/task_mmu.c                 | 106 ++++++++++++++++++++++++++++++++++++-
 mm/hugetlb.c                       |  11 ++++
 3 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index adba21b..a11ab80 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -423,6 +423,9 @@ SwapPss:               0 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB
 Locked:                0 kB
+Ptes@4kB:	       4 kB
+Ptes@2MB:	    8192 kB
+
 VmFlags: rd ex mr mw me dw
 
 the first of these lines shows the same information as is displayed for the
@@ -460,6 +463,9 @@ replaced by copy-on-write) part of the underlying shmem object out on swap.
 "SwapPss" shows proportional swap share of this mapping. Unlike "Swap", this
 does not take into account swapped out page of underlying shmem objects.
 "Locked" indicates whether the mapping is locked in memory or not.
+"Ptes@..." lines show how many page table entries are currently in place and
+pointing to memory.  There is an entry for each size present in the hardware
+page tables for this mapping.
 
 "VmFlags" field deserves a separate description. This member represents the kernel
 flags associated with the particular virtual memory area in two letter encoded
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 5589b4b..30dbf37 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -451,6 +451,9 @@ struct mem_size_stats {
 	unsigned long shared_hugetlb;
 	unsigned long private_hugetlb;
 	unsigned long first_vma_start;
+	unsigned long rss_pte;
+	unsigned long rss_pmd;
+	unsigned long rss_pud;
 	u64 pss;
 	u64 pss_locked;
 	u64 swap_pss;
@@ -529,6 +532,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
 
 	if (pte_present(*pte)) {
 		page = vm_normal_page(vma, addr, *pte);
+		mss->rss_pte += PAGE_SIZE;
 	} else if (is_swap_pte(*pte)) {
 		swp_entry_t swpent = pte_to_swp_entry(*pte);
 
@@ -590,6 +594,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
 		/* pass */;
 	else
 		VM_BUG_ON_PAGE(1, page);
+	mss->rss_pmd += PMD_SIZE;
 	smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd));
 }
 #else
@@ -699,6 +704,30 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
+/*
+ * Most architectures have a 1:1 mapping of PTEs to hugetlb page
+ * sizes, but there are some outliers like arm64 that use
+ * multiple hardware PTEs to make a hugetlb "page".  Do not
+ * assume that all 'hpage_size's are not exactly at a page table
+ * size boundary.  Instead, accept arbitrary 'hpage_size's and
+ * assume they are made up of the next-smallest size.  We do not
+ * handle PGD-sized hpages and hugetlb_add_hstate() will WARN()
+ * if it sees one.
+ *
+ * Note also that the page walker code only calls us once per
+ * huge 'struct page', *not* once per PTE in the page tables.
+ */
+static void smaps_hugetlb_present_hpage(struct mem_size_stats *mss,
+					unsigned long hpage_size)
+{
+	if (hpage_size >= PUD_SIZE)
+		mss->rss_pud += hpage_size;
+	else if (hpage_size >= PMD_SIZE)
+		mss->rss_pmd += hpage_size;
+	else
+		mss->rss_pte += hpage_size;
+}
+
 static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 				 unsigned long addr, unsigned long end,
 				 struct mm_walk *walk)
@@ -719,11 +748,14 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 	}
 	if (page) {
 		int mapcount = page_mapcount(page);
+		unsigned long hpage_size = huge_page_size(hstate_vma(vma));
+
+		smaps_hugetlb_present_hpage(mss, hpage_size);
 
 		if (mapcount >= 2)
-			mss->shared_hugetlb += huge_page_size(hstate_vma(vma));
+			mss->shared_hugetlb += hpage_size;
 		else
-			mss->private_hugetlb += huge_page_size(hstate_vma(vma));
+			mss->private_hugetlb += hpage_size;
 	}
 	return 0;
 }
@@ -733,6 +765,75 @@ void __weak arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
 {
 }
 
+/*
+ * What units should we use for a given number?  We want
+ * 2048 to be 2k, so we return 'k'.  1048576 should be
+ * 1M, so we return 'M'.
+ */
+static char size_unit(unsigned long long nr)
+{
+	/*
+	 * This ' ' might look a bit goofy in the output.  But, why
+	 * bother doing anything.  Do we even have a <1k page size?
+	 */
+	if (nr < (1ULL<<10))
+		return ' ';
+	if (nr < (1ULL<<20))
+		return 'k';
+	if (nr < (1ULL<<30))
+		return 'M';
+	if (nr < (1ULL<<40))
+		return 'G';
+	if (nr < (1ULL<<50))
+		return 'T';
+	if (nr < (1ULL<<60))
+		return 'P';
+	return 'E';
+}
+
+/*
+ * How should we shift down a a given number to scale it
+ * with the units we are printing it as? 2048 to be 2k,
+ * so we want it shifted down by 10.  1048576 should be
+ * 1M, so we want it shifted down by 20.
+ */
+static int size_shift(unsigned long long nr)
+{
+	if (nr < (1ULL<<10))
+		return 0;
+	if (nr < (1ULL<<20))
+		return 10;
+	if (nr < (1ULL<<30))
+		return 20;
+	if (nr < (1ULL<<40))
+		return 30;
+	if (nr < (1ULL<<50))
+		return 40;
+	if (nr < (1ULL<<60))
+		return 50;
+	return 60;
+}
+
+static void show_one_smap_pte(struct seq_file *m, unsigned long bytes_rss,
+		unsigned long pte_size)
+{
+	seq_printf(m, "Ptes@%ld%cB:	%8lu kB\n",
+			pte_size >> size_shift(pte_size),
+			size_unit(pte_size),
+			bytes_rss >> 10);
+}
+
+static void show_smap_ptes(struct seq_file *m, struct mem_size_stats *mss)
+{
+	/* Only print the entries for page sizes present in the VMA */
+	if (mss->rss_pte)
+		show_one_smap_pte(m, mss->rss_pte, PAGE_SIZE);
+	if (mss->rss_pmd)
+		show_one_smap_pte(m, mss->rss_pmd, PMD_SIZE);
+	if (mss->rss_pud)
+		show_one_smap_pte(m, mss->rss_pud, PUD_SIZE);
+}
+
 static int show_smap(struct seq_file *m, void *v, int is_pid)
 {
 	struct proc_maps_private *priv = m->private;
@@ -852,6 +953,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
 			   (unsigned long)(mss->pss >> (10 + PSS_SHIFT)));
 
 	if (!rollup_mode) {
+		show_smap_ptes(m, mss);
 		arch_show_smap(m, vma);
 		show_smap_vma_flags(m, vma);
 	}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 424b0ef..b98b2ce 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2836,6 +2836,17 @@ void __init hugetlb_add_hstate(unsigned int order)
 					huge_page_size(h)/1024);
 
 	parsed_hstate = h;
+
+	/*
+	 * PGD_SIZE isn't widely made available by architecures,
+	 * so use PUD_SIZE*PTRS_PER_PUD as a substitute.
+	 *
+	 * Check for sizes that might be mapped by a PGD.  There
+	 * are none of these known today, but be on the lookout.
+	 * If this trips, we will need to update the mss->rss_*
+	 * code in fs/proc/task_mmu.c.
+	 */
+	WARN_ON_ONCE((PAGE_SIZE << order) >= PUD_SIZE * PTRS_PER_PUD);
 }
 
 static int __init hugetlb_nrpages_setup(char *s)
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCHv2 2/2] Add /proc/PID/{smaps, numa_maps} support for DAX
  2017-10-24 10:49 [PATCHv2 1/2] proc: mm: export PTE sizes directly in smaps Fan Du
@ 2017-10-24 10:49 ` Fan Du
  2017-10-27  6:48   ` kbuild test robot
  0 siblings, 1 reply; 3+ messages in thread
From: Fan Du @ 2017-10-24 10:49 UTC (permalink / raw)
  To: akpm, hch, dan.j.williams, dave.hansen; +Cc: linux-kernel, Fan Du

So user could check those interface for more detailed
information about how much DAX mappings are currently
created.

Here we use vma_is_dax method to find specific page
struture with DAX {huge, normal}page mappings,
vm_normal_page routine works as before without any
impact on the existing logical where _vm_normal_page
are called.

Signed-off-by: Fan Du <fan.du@intel.com>
---
v2:
* Using pte_devmap to check valid pfn page structure,
  Pointed out by Dan. thx!

---
 fs/proc/task_mmu.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 30dbf37..5c4535c 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -531,7 +531,10 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
 	struct page *page = NULL;
 
 	if (pte_present(*pte)) {
-		page = vm_normal_page(vma, addr, *pte);
+		if (!vma_is_dax(vma))
+			page = vm_normal_page(vma, addr, *pte);
+		else if (pte_devmap(*pte))
+			page = pte_page(*pte);
 		mss->rss_pte += PAGE_SIZE;
 	} else if (is_swap_pte(*pte)) {
 		swp_entry_t swpent = pte_to_swp_entry(*pte);
@@ -583,7 +586,11 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
 	struct page *page;
 
 	/* FOLL_DUMP will return -EFAULT on huge zero page */
-	page = follow_trans_huge_pmd(vma, addr, pmd, FOLL_DUMP);
+	if (!vma_is_dax(vma))
+		page = follow_trans_huge_pmd(vma, addr, pmd, FOLL_DUMP);
+	else if (pmd_devmap(*pmd))
+		page = pmd_page(*pmd);
+
 	if (IS_ERR_OR_NULL(page))
 		return;
 	if (PageAnon(page))
@@ -1770,13 +1777,15 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
 	spinlock_t *ptl;
 	pte_t *orig_pte;
 	pte_t *pte;
+	struct page *page;
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	ptl = pmd_trans_huge_lock(pmd, vma);
 	if (ptl) {
-		struct page *page;
-
-		page = can_gather_numa_stats_pmd(*pmd, vma, addr);
+		if (!vma_is_dax(vma))
+			page = can_gather_numa_stats_pmd(*pmd, vma, addr);
+		else if (pmd_devmap(*pmd))
+			page = pmd_page(*pmd);
 		if (page)
 			gather_stats(page, md, pmd_dirty(*pmd),
 				     HPAGE_PMD_SIZE/PAGE_SIZE);
@@ -1789,7 +1798,10 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
 #endif
 	orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
 	do {
-		struct page *page = can_gather_numa_stats(*pte, vma, addr);
+		if (!vma_is_dax(vma))
+			page = can_gather_numa_stats(*pte, vma, addr);
+		else if (pte_devmap(*pte))
+			page = pte_page(*pte);
 		if (!page)
 			continue;
 		gather_stats(page, md, pte_dirty(*pte), 1);
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCHv2 2/2] Add /proc/PID/{smaps, numa_maps} support for DAX
  2017-10-24 10:49 ` [PATCHv2 2/2] Add /proc/PID/{smaps, numa_maps} support for DAX Fan Du
@ 2017-10-27  6:48   ` kbuild test robot
  0 siblings, 0 replies; 3+ messages in thread
From: kbuild test robot @ 2017-10-27  6:48 UTC (permalink / raw)
  To: Fan Du
  Cc: kbuild-all, akpm, hch, dan.j.williams, dave.hansen, linux-kernel, Fan Du

[-- Attachment #1: Type: text/plain, Size: 5823 bytes --]

Hi Fan,

Thank you for the patch! Yet we hit a small issue.
[auto build test WARNING on linus/master]
[also build test WARNING on v4.14-rc6 next-20171018]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Fan-Du/proc-mm-export-PTE-sizes-directly-in-smaps/20171027-141157
config: x86_64-randconfig-x011-201743 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   fs/proc/task_mmu.c: In function 'gather_pte_stats':
>> fs/proc/task_mmu.c:1805:6: warning: 'page' may be used uninitialized in this function [-Wmaybe-uninitialized]
      if (!page)
         ^

vim +/page +1805 fs/proc/task_mmu.c

28093f9f3 Gerald Schaefer    2016-04-28  1771  
f69ff943d Stephen Wilson     2011-05-24  1772  static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
f69ff943d Stephen Wilson     2011-05-24  1773  		unsigned long end, struct mm_walk *walk)
f69ff943d Stephen Wilson     2011-05-24  1774  {
d85f4d6d3 Naoya Horiguchi    2015-02-11  1775  	struct numa_maps *md = walk->private;
d85f4d6d3 Naoya Horiguchi    2015-02-11  1776  	struct vm_area_struct *vma = walk->vma;
f69ff943d Stephen Wilson     2011-05-24  1777  	spinlock_t *ptl;
f69ff943d Stephen Wilson     2011-05-24  1778  	pte_t *orig_pte;
f69ff943d Stephen Wilson     2011-05-24  1779  	pte_t *pte;
3bf801467 Fan Du             2017-10-24  1780  	struct page *page;
f69ff943d Stephen Wilson     2011-05-24  1781  
28093f9f3 Gerald Schaefer    2016-04-28  1782  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
b6ec57f4b Kirill A. Shutemov 2016-01-21  1783  	ptl = pmd_trans_huge_lock(pmd, vma);
b6ec57f4b Kirill A. Shutemov 2016-01-21  1784  	if (ptl) {
3bf801467 Fan Du             2017-10-24  1785  		if (!vma_is_dax(vma))
28093f9f3 Gerald Schaefer    2016-04-28  1786  			page = can_gather_numa_stats_pmd(*pmd, vma, addr);
3bf801467 Fan Du             2017-10-24  1787  		else if (pmd_devmap(*pmd))
3bf801467 Fan Du             2017-10-24  1788  			page = pmd_page(*pmd);
32ef43848 Dave Hansen        2011-09-20  1789  		if (page)
28093f9f3 Gerald Schaefer    2016-04-28  1790  			gather_stats(page, md, pmd_dirty(*pmd),
32ef43848 Dave Hansen        2011-09-20  1791  				     HPAGE_PMD_SIZE/PAGE_SIZE);
bf929152e Kirill A. Shutemov 2013-11-14  1792  		spin_unlock(ptl);
32ef43848 Dave Hansen        2011-09-20  1793  		return 0;
32ef43848 Dave Hansen        2011-09-20  1794  	}
32ef43848 Dave Hansen        2011-09-20  1795  
1a5a9906d Andrea Arcangeli   2012-03-21  1796  	if (pmd_trans_unstable(pmd))
1a5a9906d Andrea Arcangeli   2012-03-21  1797  		return 0;
28093f9f3 Gerald Schaefer    2016-04-28  1798  #endif
f69ff943d Stephen Wilson     2011-05-24  1799  	orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
f69ff943d Stephen Wilson     2011-05-24  1800  	do {
3bf801467 Fan Du             2017-10-24  1801  		if (!vma_is_dax(vma))
3bf801467 Fan Du             2017-10-24  1802  			page = can_gather_numa_stats(*pte, vma, addr);
3bf801467 Fan Du             2017-10-24  1803  		else if (pte_devmap(*pte))
3bf801467 Fan Du             2017-10-24  1804  			page = pte_page(*pte);
f69ff943d Stephen Wilson     2011-05-24 @1805  		if (!page)
f69ff943d Stephen Wilson     2011-05-24  1806  			continue;
eb4866d00 Dave Hansen        2011-09-20  1807  		gather_stats(page, md, pte_dirty(*pte), 1);
f69ff943d Stephen Wilson     2011-05-24  1808  
f69ff943d Stephen Wilson     2011-05-24  1809  	} while (pte++, addr += PAGE_SIZE, addr != end);
f69ff943d Stephen Wilson     2011-05-24  1810  	pte_unmap_unlock(orig_pte, ptl);
a66c0410b Hugh Dickins       2016-12-12  1811  	cond_resched();
f69ff943d Stephen Wilson     2011-05-24  1812  	return 0;
f69ff943d Stephen Wilson     2011-05-24  1813  }
f69ff943d Stephen Wilson     2011-05-24  1814  #ifdef CONFIG_HUGETLB_PAGE
632fd60fe Naoya Horiguchi    2015-02-11  1815  static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
f69ff943d Stephen Wilson     2011-05-24  1816  		unsigned long addr, unsigned long end, struct mm_walk *walk)
f69ff943d Stephen Wilson     2011-05-24  1817  {
5c2ff95e4 Michael Holzheu    2016-02-02  1818  	pte_t huge_pte = huge_ptep_get(pte);
f69ff943d Stephen Wilson     2011-05-24  1819  	struct numa_maps *md;
f69ff943d Stephen Wilson     2011-05-24  1820  	struct page *page;
f69ff943d Stephen Wilson     2011-05-24  1821  
5c2ff95e4 Michael Holzheu    2016-02-02  1822  	if (!pte_present(huge_pte))
f69ff943d Stephen Wilson     2011-05-24  1823  		return 0;
f69ff943d Stephen Wilson     2011-05-24  1824  
5c2ff95e4 Michael Holzheu    2016-02-02  1825  	page = pte_page(huge_pte);
f69ff943d Stephen Wilson     2011-05-24  1826  	if (!page)
f69ff943d Stephen Wilson     2011-05-24  1827  		return 0;
f69ff943d Stephen Wilson     2011-05-24  1828  
f69ff943d Stephen Wilson     2011-05-24  1829  	md = walk->private;
5c2ff95e4 Michael Holzheu    2016-02-02  1830  	gather_stats(page, md, pte_dirty(huge_pte), 1);
f69ff943d Stephen Wilson     2011-05-24  1831  	return 0;
f69ff943d Stephen Wilson     2011-05-24  1832  }
f69ff943d Stephen Wilson     2011-05-24  1833  

:::::: The code at line 1805 was first introduced by commit
:::::: f69ff943df6972aae96c10733b6847fa094d8a59 mm: proc: move show_numa_map() to fs/proc/task_mmu.c

:::::: TO: Stephen Wilson <wilsons@start.ca>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 30524 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-10-27  6:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-24 10:49 [PATCHv2 1/2] proc: mm: export PTE sizes directly in smaps Fan Du
2017-10-24 10:49 ` [PATCHv2 2/2] Add /proc/PID/{smaps, numa_maps} support for DAX Fan Du
2017-10-27  6:48   ` kbuild test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome