* [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