[RFC][PATCH] up unpinned mmap usable address space from 2 to 3 GB

From: Joe Korty
Date: Thu Jun 17 2004 - 16:19:07 EST


Make the full 3 GB of process address space available to unpinned mmaps.
Previously only the 2 GB from 40000000-c0000000 was available.

The process address space allocation behavior should remain unchanged
for non-i386 architectures.

For i386, the new algorithm first allocates from virtual address 40000000
to the start of the stack area (as defined by ulimit -s), then from the
start of the text area (08000000) down to 00400000, then from 40000000
down to the sbrk area, then (as a last resort) starts allocating from
the unused portion of the stack area.

With this patch, a small java program, simulating a real application,
can spin off 3,790 threads. Previously, only 1,750 threads could be
spun off.

Due to the fragility of making changes to get_unmapped_area(), this patch
is intended 'For Comment Only'.

Against 2.6.7.

Regards,
Joe

================== Test.java

public class Test
{
private static int threadCounter = 0;

public static synchronized int getThreadNumber() {
return threadCounter++;
}

public static void main(String [] args) {
for(int i = 0; i < 6000; i++) {
new Thread(new Runnable() {
public void run() {
System.err.println("Thread " + getThreadNumber());
while(true) {
try {
Thread.currentThread().sleep(10000);
} catch(InterruptedException ie) {
// Don't care
}
}
}
}
).start();
}
}
}

================== compilation instructions

Download Java 2 SDK 1.4.2_04 linux i586 from java.sun.com, install
javac Test.java
java -Xmx1000M -Xms1000M -cp . Test

================== patch

diff -ura base/include/asm-i386/processor.h new/include/asm-i386/processor.h
--- base/include/asm-i386/processor.h 2004-06-16 01:18:56.000000000 -0400
+++ new/include/asm-i386/processor.h 2004-06-17 12:47:01.000000000 -0400
@@ -301,6 +301,9 @@
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
+#define TASK_UNMAPPED_BASE_2 (PAGE_ALIGN(16 * PAGE_SIZE))
+#define TASK_SLOP_FUNCTION (current->rlim[RLIMIT_STACK].rlim_cur)
+#define MIN_TASK_SLOP (64 * PAGE_SIZE)

/*
* Size of io_bitmap, covering ports 0 to 0x3ff.
diff -ura base/mm/mmap.c new/mm/mmap.c
--- base/mm/mmap.c 2004-06-16 01:19:37.000000000 -0400
+++ new/mm/mmap.c 2004-06-17 12:45:52.000000000 -0400
@@ -1002,13 +1002,26 @@
* This function "knows" that -ENOMEM has the bits set.
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
+
+#ifndef TASK_UNMAPPED_BASE_2
+#define TASK_UNMAPPED_BASE_2 TASK_UNMAPPED_BASE
+#endif
+
+#ifndef MIN_TASK_SLOP
+#define MIN_TASK_SLOP 1 /* must be >0 */
+#endif
+
+#ifndef TASK_SLOP_FUNCTION
+#define TASK_SLOP_FUNCTION 0
+#endif
+
static inline unsigned long
arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
- unsigned long start_addr;
+ unsigned long start_addr, end_addr, end_slop;

if (len > TASK_SIZE)
return -ENOMEM;
@@ -1020,27 +1033,45 @@
(!vma || addr + len <= vma->vm_start))
return addr;
}
+ /* determine how close to TASK_SIZE we are willing to get */
+ end_slop = TASK_SLOP_FUNCTION;
+ if (end_slop < MIN_TASK_SLOP)
+ end_slop = MIN_TASK_SLOP;
+ end_slop = PAGE_ALIGN(end_slop);
+
+ end_addr = TASK_SIZE - end_slop;
start_addr = addr = mm->free_area_cache;

full_search:
for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */
- if (TASK_SIZE - len < addr) {
+ if (end_addr - len < addr) {
/*
* Start a new search - just in case we missed
* some holes.
*/
- if (start_addr != TASK_UNMAPPED_BASE) {
+ if (end_addr == TASK_SIZE)
+ return -ENOMEM;
+ end_addr = start_addr;
+ if (start_addr > TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
- goto full_search;
+ } else if (start_addr > TASK_UNMAPPED_BASE_2) {
+ /* dig a bit into the sbrk area if necessary */
+ start_addr = addr = TASK_UNMAPPED_BASE_2;
+ } else {
+ /* dig into the stack area as a last resort */
+ end_addr = TASK_SIZE;
+ addr = TASK_SIZE - end_slop;
}
- return -ENOMEM;
+ goto full_search;
}
if (!vma || addr + len <= vma->vm_start) {
- /*
- * Remember the place where we stopped the search:
- */
- mm->free_area_cache = addr + len;
+ if (addr >= TASK_UNMAPPED_BASE) {
+ mm->free_area_cache = addr + len;
+ } else {
+ mm->free_area_cache = addr;
+ addr = (vma ? vma->vm_start : end_addr) - len;
+ }
return addr;
}
addr = vma->vm_end;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/