Skip to contentSkip to conversation

export NUMA allocation fragmentation

PATCH New Dave Hansen 1 participant 1 message Jan 31, 2003

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

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
diff -ru linux-2.5.59-mjb2-clean/fs/proc/base.c linux-2.5.59-mjb2-vma-stat/fs/proc/base.c
@@ -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
diff -ru linux-2.5.59-mjb2-clean/include/asm-i386/mmzone.h linux-2.5.59-mjb2-vma-stat/include/asm-i386/mmzone.h
@@ -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
diff -ru linux-2.5.59-mjb2-clean/mm/memory.c linux-2.5.59-mjb2-vma-stat/mm/memory.c
@@ -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;
 }