export NUMA allocation fragmentation
Subsystems (4)
PATCH 1/1 export NUMA allocation fragmentation
The NUMA memory allocation support attempts to allocate pages close to the CPUs that it is currently running on. We have a hard time determining how effective these strategies have been, or how fragmented the allocations might get if a process is bounced around between nodes.
This patch adds a new /proc/<pid> entry: nodepages.
It walks the process's vm_area_structs for all vaddr ranges, then examines the ptes to determine on which node each virtual address physically resides.
I'm a little worried about just taking the pte from __follow_page() and dumping it into pte_pfn(). Is there something I should be testing for, before I feed it along?
I've tested it on both NUMA and non-NUMA systems (see the pfn_to_nid() changes). The below are from a 4-quad 16-proc NUMAQ.
This is a process that allocates, then faults in a 256MB chunk of memory, bound to CPU 4 (node 1).
curly:~# cat /proc/378/nodepages Node 0 pages: 369 Node 1 pages: 65571 Node 2 pages: 0 Node 3 pages: 0
Here is the same thing, bound to CPU12 (node 3), probably forked on node 1, before it was bound.
Node 0 pages: 369
Node 1 pages: 2
Node 2 pages: 0
Node 3 pages: 65569
I would imagine that the pages on node 0 are from libc, which was originally mapped on node 0. The other processes inherit this.
Signature · 2 lines
Dave Hansen [email protected]
fs/proc/base.c +7 -0
@@ -45,6 +45,7 @@enum pid_directory_inos {PROC_PID_INO =2 ,PROC_PID_STATUS , +PROC_PID_NODE_PAGES ,PROC_PID_MEM ,PROC_PID_CWD ,PROC_PID_ROOT ,
@@ -72,6 +73,7 @@E (PROC_PID_FD ,"fd" ,S_IFDIR |S_IRUSR |S_IXUSR ),E (PROC_PID_ENVIRON ,"environ" ,S_IFREG |S_IRUSR ),E (PROC_PID_STATUS ,"status" ,S_IFREG |S_IRUGO ), +E (PROC_PID_NODE_PAGES ,"nodepages" ,S_IFREG |S_IRUGO ),E (PROC_PID_CMDLINE ,"cmdline" ,S_IFREG |S_IRUGO ),E (PROC_PID_STAT ,"stat" ,S_IFREG |S_IRUGO ), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO),
@@ -102,6 +104,7 @@int proc_pid_status (struct task_struct *,char *);int proc_pid_statm (struct task_struct *,char *);int proc_pid_cpu (struct task_struct *,char *); +int proc_pid_nodepages (struct task_struct *,char *);static int proc_fd_link (struct inode *inode,struct dentry **dentry,struct vfsmount **mnt) {
@@ -1012,6 +1015,10 @@case PROC_PID_STATUS : inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_status; +break ; +case PROC_PID_NODE_PAGES : + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_nodepages;break ;case PROC_PID_STAT : inode->i_fop = &proc_info_file_operations;
fs/proc/task_mmu.c +52 -0
63 lines not on this page · raw message
include/asm-i386/mmzone.h +5 -2
@@ -8,14 +8,17 @@#include <asm/smp.h> -#ifdef CONFIG_DISCONTIGMEM +#ifndef CONFIG_DISCONTIGMEM + +#define pfn_to_nid (pfn) (0) + +#else #ifdef CONFIG_X86_NUMAQ #include <asm/numaq.h> #elif CONFIG_X86_SUMMIT #include <asm/srat.h> #else -#define pfn_to_nid (pfn) (0)#endif /* CONFIG_X86_NUMAQ */ extern struct pglist_data *node_data[];
mm/memory.c +18 -6
@@ -612,13 +612,12 @@* Do a quick page-table lookup for a single page. * mm->page_table_lock must be held. */ -struct page * -follow_page (struct mm_struct *mm,unsigned long address,int write) +pte_t +__follow_page (struct mm_struct *mm,unsigned long address) {pgd_t *pgd;pmd_t *pmd;pte_t *ptep, pte; -unsigned long pfn; pgd =pgd_offset (mm, address);if (pgd_none (*pgd) ||pgd_bad (*pgd))
@@ -629,11 +628,25 @@ goto out; ptep =pte_offset_map (pmd, address); -if (!ptep) +if (!ptep) { + pte.pte_low =0 ;//__bad_page(); + pte.pte_high =0 ; goto out; - + } pte = *ptep;pte_unmap (ptep); + +out: +return pte; +} + +struct page * +follow_page (struct mm_struct *mm,unsigned long address,int write) +{ +pte_t pte; +unsigned long pfn; + + pte =__follow_page (mm, address);if (pte_present (pte)) {if (!write || (pte_write (pte) &&pte_dirty (pte))) { pfn =pte_pfn (pte);
@@ -642,7 +655,6 @@ } } -out:return NULL ; }